Anonymous scopes were mentioned briefly on Ryan's Scraps. And in the API, I found it tucked away in ActiveRecord::NamedScope module documentation.
All subclasses of ActiveRecord::Base have two named_scopes:How would this be useful? In the example given, it's really not. And most of the time, what you need to do will suffice with named scope. However, there are times when named scope doesn't give you the flexibility that you need, and it is actually quite powerful when it's used in conjunction with association proxies.These anonymous scopes tend to be useful when procedurally generating complex queries, where passing intermediate values (scopes) around as first-class objects is convenient.
- all, which is similar to a find(:all) query, and
- scoped, which allows for the creation of anonymous scopes, on the fly:
Shirt.scoped(:conditions => {:color => ‘red’}).scoped(:include => :washing_instructions)
I was using the better nested set plugin. It allows you to have a fast access tree structure in a relational database. And while it's a neat plugin, I couldn't chain my calls like such:
@father.subtree.with_email # => fails
to find all the father's descendants that had an email. That's because subtree() exists in the plugin and it uses find(), and that returns an array of objects. You can't further extend the call, because by find returns an array, not an association proxy.
In our association proxies, if we expect to chain the calls, we can use scoped() instead of find(). Just to demonstrate:
class Person < ActiveRecord::Base
has_many :people do
def subtree
scoped(:conditions => ["lft between self.id and self.id", self.lft, self.rgt])
end
end
named_scope :with_emails, :conditions => ["email is not null"]
end
That means we would be able to change other scoped after subtree():
@father.subtree.with_emails # => returns all children
There's not much to it, but it's nice when, once again, you're into breaking Law of Demeter.
tip!
>That's because subtree() exists in the plugin and it uses find()
ReplyDeleteI can't find subtree() method in better nested set plugin's API.
Ahh, sorry, the subtree() was a wrapper in my code. It's actually called full_set() or all_children() in the API, depending on whether you want to include that node.
ReplyDelete