Beware of chaining lambda scopes
Here’s a gotcha to watch out for! Let’s say you have these scopes in your Rails 3 project:
scope :started, lambda { where("starting_at <= ?", Time.now) }
scope :unfinished, lambda { where("ending_at > ?", Time.now) }
When you call either of these scopes, because you have used lambda, the value of the lambda is re-evaluated each time so that Time.now is dynamic. That’s what you want and what you expect.
Now, when you chain these scopes together:
Event.started.unfinished
The value of Time.now will be re-evaluated each time this is run which is what you want and what you expect.
You end up using this a bit, so you decide to wrap it up into its own scope:
scope :active, started.unfinished
Unfortunately, when you use this new scope, the value of Time.now has now become static which is not what you wanted. You need to use a lambda for the same reason you did with the original scopes.
scope :active, lambda { started.unfinished }
When you think about it, it makes sense. The value of the scope is evaluated at the time the scope is defined. So with the first definition of active, the lambdas in the started and unfinished scopes were evaluated. You need to defer that evaluation, hence the need to wrap those calls inside a lambda as well.
(Source: rails.lighthouseapp.com)