In my Rails 3.2.8 app I have some named scopes I would like to chain together in some circumstances.
So, for example, I have these two scopes:
scope :by_status, lambda { |status| if status == "All" then WorkRequest.all else WorkRequest.find_all_by_status(status) end }
scope :in_date_range, lambda { |start_date, end_date| includes([:person, :pier_module]).where("(status_date >= ?) AND (status_date <= ?)", start_date, end_date) }
I use them separately, but I'd also like to be able to call them together like this:
WorkRequest.by_status("Accepted").in_date_range("2012-01-01", "2012-10-02")
When I try that it complains that in_date_range is not a method of Array.
But I have another scope,
scope :active, includes([:person, :pier_module]).where("status = 'New Request'")
and if I do
WorkRequest.active.in_date_range("2012-01-01", "2012-10-02")
it works! Apparently the active scope returns a Relation, whereas the lambda scopes return Arrays, and so can't be chained.
I'd love to know why the difference between simpler scopes and lambda scopes, how the parameters affect it, and whether there's anything I can do short of writing a combined scope, which I've done.
scope :by_status_in_date_range, lambda { |status, start_date, end_date| includes([:person, :pier_module]).where("(status = ?) AND (status_date >= ?) AND (status_date <= ?)", status, start_date, end_date) }
Works, but not very DRY (since I need the individual scopes, too) or Rails-ish. Searching here and elsewhere I've seen similar questions but none that seem to apply to this situation, where I'm trying to chain two lambdas with parameters.
That happens because in your scope
scope :by_status, lambda { |status| if status == "All" then WorkRequest.all else WorkRequest.find_all_by_status(status) end }
metods all
and find_all_by_status
returns Array
instead of ActiveRecord::Relation
. You should replace it with where
for example.
scope :by_status, lambda { |status| where(:status => status) unless status == "All" }