rails scope "expires_within"
Hey guys. I have a model, Item
, which is set to "expire" in created_at + 100.days
. I am trying to create a scope that will return the items which will expire in a supplied time, such as 10.days
.
So far I have this:
scope :expires_within, lambda {|time| where("created_at > ?", time)}
So that I could eventually do something like:
Item.expires_within(10.days)
Which would return a collection of items which expire within 10 days.
This isn't right, I just wanted to have a skeleton of what I should have. I can't figure out if it's possible to do this through a scope or not. It seems to me like I would be able to if I had a column in the table called expires_at
, but the problem is that I would rather not create such a column becau开发者_运维问答se I want the expiration time, above stated as created_at + 100.days
, to be flexible.
I just wanted to see if it would be possible without such a column, or if it can be done but not with a scope, I'd like to hear that possibility as well. If not, I'll go ahead and add it.
from_now
would do this:
10.days.from_now
Or dynamically:
scope :expires_within, lambda {|time| where("created_at > ?", time.from_now)}
You could create a scope for...
scope :expires_within_10_days, lambda { where('created at > ?', 90.days.ago) }
...which should fetch all items that were created over 90 days ago, which means they expire within 10 days. Add another condition to exclude already-expired items.
Update: Switched example to a scope, versus regular AR query...
I have come up with a solution I believe. I will continue to test it.
scope :expires_within, lambda {|time| where("created_at < ?", time.from_now - 100.days)}
Basically my original formula to calculate whether something was expired was:
Time.now > created_at + 100.days
Since I want to determine whether something expires within a future time (e.g. 10.days), I add it to the left-hand side:
Time.now + time > created_at + 100.days
Remember, 100.days is how long an item has to live before it expires.
Finally, I solve for created_at
so that it's by itself, since that's what the sql query demands, by subtracting 100.days
from the other side:
created_at < (Time.now + time) - 100.days
This could be made more concise, as Ryan pointed out, by doing:
created_at < time.from_now - 100.days
Basic math I guess. I'm still pretty dazed from thinking about it too hard, so I will test it a bit to make sure it works as intended. If it does, Item.expires_within(10.days)
should return a collection of items which will expire within 10 days (or before).
EDIT: I've refactored this to ignore the items which have already expired. So the new scope looks for the items that have not yet expired and will expire within a specified time frame:
scope :expires_within, lambda {|time| where("created_at BETWEEN ? AND ?", 100.days.ago, time.from_now - 100.days)}
精彩评论