For reference, here it is (but really, read his post):
class Organization < ActiveRecord::Base has_many :people do def find_active find(:all, :conditions => ["active = ?", true]) end end end
Ryan then shows us his new superpower: organization.people.find_active (where organization is something normal like Organization.find(:first)). Makes sense, right? You can just slap whatever methods you want onto an association to make them More Powerful™.
So, that’s a pretty good use. Custom finder and all that. But we can get crazier than just finders.
Take, oh I dunno, tags. Let’s say you have a normal blog which has and belongs to many tags. Comma separated tags.
class Post < ActiveRecord::Base has_and_belongs_to_many :tags end
Now I can do Post.find(:first).tags to get an array of tags. Nothing special. How would you get a string of tags in a view?Maybe:
<%= @post.tags.map(&:name).join(', ') %>
That’s one way. But as you and I are on this skinny controller fat model kick, we know the better solution is to add a method like tags_string to our Post model.
class Post < ActiveRecord::Base has_and_belongs_to_many :tags def tags_string tags.map(&:name) * ', ' end end
Now, our view:
<%= @post.tags_string %>
Nice. A clean, comma separated list of tag names. The acts_as_taggable plugin includes a tags_list method by default which does this same thing (albeit space separated).
But wait. Wait. What <%= %> does, behind the scenes, is call to_s on what’s passed to it. Knowing that, we can control how objects are <%= %>‘d by overriding their to_s. You’d never want to <%= @post.tags %> because it would just print a bunch of debug crap. Hrm… it sure reads nicely, though…
What if we did this…
class Post < ActiveRecord::Base has_and_belongs_to_many :tags do def to_s map(&:name) * ', ' end end endNow we can just do this in our view to get a comma separated list of tags:
<%= @post.tags %>Or, in script/console:
>> @post.tags.class => Array >> @post.tags.size => 2 >> @post.tags.to_s => "bikes, site"
Hot. Extending associations ain’t just for finders no more.
Update: Wow, sloppy. For the record it’s &:name, not :&name. Fixed it up.