Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding "find" in ActiveRecord the DRY way

I have a few models that need to have custom find conditions placed on them. For example, if I have a Contact model, every time Contact.find is called, I want to restrict the contacts returned that only belong to the Account in use.

I found this via Google (which I've customized a little):

def self.find(*args)
  with_scope(:find => { :conditions =>  "account_id = #{$account.id}" }) do
    super(*args)
  end
end

This works great, except for a few occasions where account_id is ambiguous so I adapted it to:

def self.find(*args)
  with_scope(:find => { :conditions =>  "#{self.to_s.downcase.pluralize}.account_id = #{$account.id}" }) do
    super(*args)
  end
end

This also works great, however, I want it to be DRY. Now I have a few different models that I want this kind of function to be used. What is the best way to do this?

When you answer, please include the code to help our minds grasp the metaprogramming Ruby-fu.

(I'm using Rails v2.1)

like image 551
Dan Harper Avatar asked Sep 17 '08 06:09

Dan Harper


1 Answers

You don't tell us which version of rails you are using [edit - it is on rails 2.1 thus following advice is fully operational], but I would recommand you use the following form instead of overloading find yourself :

account.contacts.find(...) 

this will automatically wrap the find in a scope where the user clause is included (since you have the account_id I assume you have the account somewhere close)

I suggest you check the following resources on scopes

  • http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-finder-functionality (this is not edge anymore :) )
  • http://ryandaigle.com/articles/2008/8/20/named-scope-it-s-not-just-for-conditions-ya-know
like image 84
Jean Avatar answered Sep 26 '22 02:09

Jean