0

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.

Dan Barron
  • 1,094
  • 2
  • 15
  • 30
  • 1
    Just out of curiosity, does `WorkRequest.in_date_range("2012-01-01", "2012-10-02").by_status("Accepted")` work? – Gazler Oct 02 '12 at 20:09
  • I does! I was too "tunnel visioned" to try it. I was convinced it was due to the lambdas, but apparently not. This is is great, I can call it that way, but still leaves me wondering why in_date_range returns a Relation, and by_status an Array. Curiouser and curiouser. – Dan Barron Oct 02 '12 at 20:12

1 Answers1

5

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" }
ck3g
  • 5,829
  • 3
  • 32
  • 52