DRY scope methods
I am using Ruby on Rails 3.0.7 and I would like to DRY (Don't Repeat Yourself) my scope methods.
In the model file I have:
class Articles::Category < ActiveRecord::Base
scope :article_related_to, lambda { |user| where('articles_categories_article_relationships.user_id = ?', user.id) }
scope :comment_related_to, lambda { |user| where('comments_articles_article_category_relationships.user_id = ?', user.id) }
has_many :comment_article_category_relationships
has_many :comments,
:class_name => 'Comments::Articles::ArticleCategoryRelationship',
:through => :comment_article_category_relationships,
:source => :comment
has_many :article_relationships
:class_name => 'Articles::Categories::ArticleRelationship',
has_many :articles,
:through => :article_relationships,
:source => :article
end
By using the above code I can do this:
@comment.article_categories.comment_related_to(@current_user)
@comment.article_categories.article_related_to(@current_user)
How can I "DRY" scopes methods in order to make possible for both :article_related_to
and :comment_related_to
to use something like the following
@comment.article_categories.related_to(@current_user)
# In order to pass the correct 开发者_StackOverflow社区"context" 'article' or 'comment' I thought
# something like
#
# @comment.article_categories.related_to(@current_user, 'article')
# @comment.article_categories.related_to(@current_user, 'comment')
#
# but, maybe, there is a way to retrieve automatically that "context" so to
# write only one "DRYed" scope method.
?
The best I can offer is the following:
scope :related_to, lambda { |user, context|
tbl = context == :article ? :articles_categories_article_relationships
: :comments_articles_article_category_relationships
where("#{tbl}.user_id = ?", user.id)
}
That gives you the @comment.article_categories.related_to(@current_user, :article)
like you suggested. But I'm in agreement with Max Williams. This obfuscates your code unnecessarily with no real gain.
If you are really eager to obfuscate your code further you can do this:
def self.method_missing(method, *args)
if method =~ /^(.*)_related_to$/
related_to(*args, $1)
else
super
end
end
def self.related_to(user, context)
through = reflections[context.to_s.pluralize.to_sym].options[:through]
tbl = reflections[through].options[:class_name].underscore.pluralize.gsub('/', '_')
where("#{tbl}.user_id = ?", user.id)
end
Please note that I believe your associations have a couple of typos. Probably should be:
has_many :comment_article_category_relationships,
:class_name => 'Comments::Articles::ArticleCategoryRelationship'
has_many :comments,
:through => :comment_article_category_relationships,
:source => :comment
has_many :article_relationships,
:class_name => 'Articles::Categories::ArticleRelationship'
has_many :articles,
:through => :article_relationships,
:source => :article
精彩评论