Question

I have

class Foo < ActiveRecord::Base
  named_scope :a, lambda { |a| :conditions => { :a => a } }
  named_scope :b, lambda { |b| :conditions => { :b => b } }
end

I'd like

class Foo < ActiveRecord::Base
  named_scope :ab, lambda { |a,b| :conditions => { :a => a, :b => b } }
end

but I'd prefer to do it in a DRY fashion. I can get the same effect by using

 Foo.a(something).b(something_else)

but it's not particularly lovely.

Was it helpful?

Solution

Well I'm still new to rails and I'm not sure exactly what you're going for here, but if you're just going for code reuse why not use a regular class method?


        def self.ab(a, b)
            a(a).b(b)
        end
    

You could make that more flexible by taking *args instead of a and b, and then possibly make one or the other optional. If you're stuck on named_scope, can't you extend it to do much the same thing?

Let me know if I'm totally off base with what you're wanting to do.

OTHER TIPS

At least since 3.2 there is a clever solution :

scope :optional, ->() {where(option: true)}
scope :accepted, ->() {where(accepted: true)}
scope :optional_and_accepted, ->() { self.optional.merge(self.accepted) }

By making it a class method you won't be able to chain it to an association proxy, like:

@category.products.ab(x, y)

An alternative is applying this patch to enable a :through option for named_scope:

named_scope :a, :conditions => {}
named_scope :b, :conditions => {}
named_scope :ab, :through => [:a, :b]

Yes Reusing named_scope to define another named_scope

I copy it here for your convenience:

You can use proxy_options to recycle one named_scope into another:

class Thing
  #...
  named_scope :billable_by, lambda{|user| {:conditions => {:billable_id => user.id } } }
  named_scope :billable_by_tom, lambda{ self.billable_by(User.find_by_name('Tom').id).proxy_options }
  #...
end

This way it can be chained with other named_scopes.

I use this in my code and it works perfectly.

I hope it helps.

@PJ: you know, I had considered that, but dismissed it because I thought I wouldn't be able to later chain on a third named scope, like so:

Foo.ab(x, y).c(z)

But since ab(x, y) returns whatever b(y) would return, I think the chain would work. Way to make me rethink the obvious!

Check out:

http://github.com/binarylogic/searchlogic

Impressive!

To be specific:

class Foo < ActiveRecord::Base
  #named_scope :ab, lambda { |a,b| :conditions => { :a => a, :b => b } }
  # alias_scope, returns a Scope defined procedurally
  alias_scope :ab, lambda {
    Foo.a.b
  }
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top