I am using Ruby on Rails 3.2.2 and I would like to retrieve / scope associated objects by "specifying" / "filtering on" an attribute value on those associated objects. That is, at this time I am using the following code:
class Article < ActiveRecord::Base
def self.search_by_title(search)
where('articles.title LIKE ?', "%#{search}%")
end
end
class ArticleAssociation < ActiveRecord::Base
def self.search_by_article_title(search)
joins(:article).where('articles.title LIKE ?', "%#{search}%")
end
end
In the above code the where('articles.title LIKE ?', "%#{search}%")
clause is repeated twice and so I thought that it may be improved with the DRY principle: is it possible to use the Article.search_by_title
method directly in the ArticleAssociation.search_by_article_title
method?
Typical use cases are:
ArticleAssociation.search_by_article_title("Sample string")
Article.search_by_title("Sample string")
Unless you change the code structure completely, no.
You could do some hacking with lambdas, but that would be more code then the code you're DRYing. There is a such thing as good refactoring, and a such thing as bad refactoring. Unless a piece of very complex or long code is used in 2 or more places, then you can worry about refactoring. Code conventions are important, but for tiny one-method-call things like that its a waste and will probably make your code more cryptic.
Though, I know that it's annoying when people don't answer your question, so here:
class Article < ActiveRecord::Base
SEARCH_BY_TITLE=lambda {|obj, search| obj.where('articles.title LIKE ?', "%#{search}%")}
def self.search_by_title(search)
SEARCH_BY_TITLE.call(self, search)
end
end
class ArticleAssociation < ActiveRecord::Base
def self.search_by_article_title(search)
Article::SEARCH_BY_TITLE.call(joins(:article),search)
end
end
That just makes a lambda as a constant that performs the where
call on a specified object. Both methods just wrap that lambda.
Note: Although this may be considered more elegant, it will decrease performance a lot, as lambdas, closures, and the extra call are expensive in a dynamic language like Ruby. But I don't think that's an issue for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With