Reputation: 65262
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.
Upvotes: 10
Views: 15048
Reputation: 733
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) }
Upvotes: 16
Reputation: 7586
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
Upvotes: 0
Reputation: 1805
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.
Upvotes: 1
Reputation:
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]
Upvotes: 1
Reputation: 65262
@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!
Upvotes: 0
Reputation: 1557
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.
Upvotes: 2