开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜