DRY范围方法

4

我正在使用Ruby on Rails 3.0.7,希望能够DRY(不要重复自己)我的作用域方法。

在模型文件中,我有:

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

通过使用上述代码,我可以做到这一点:
@comment.article_categories.comment_related_to(@current_user)
@comment.article_categories.article_related_to(@current_user)

我该如何“DRY”范围方法,以便:article_related_to:comment_related_to都可以使用类似以下的内容?
@comment.article_categories.related_to(@current_user)

# In order to pass the correct "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.

?


1
哎呀,我眼睛都要出血了,只是试图保持这个东西的顺序!你能否通过 @current_user 对象直接获取你要查找的内容? - dogenpunk
@dogenpunk - 顺便说一句:“我都快看花眼了,试着保持这玩意儿的连续性!”...你是什么意思?- 在我的情况下,我可以通过“@current_user”对象获得我要查找的内容,但在另一方面,我会遇到与问题描述相同的问题。 - Backo
1
我个人认为这是过于追求DRY原则了:对我来说,可读性比DRY更重要,而这样做会使代码变得更难阅读。DRY应该是关于将功能或值等放在一个地方,而不是最小化代码行数。 - Max Williams
1个回答

1
我能提供的最好的是以下内容:
scope :related_to, lambda { |user, context|
  tbl = context == :article ? :articles_categories_article_relationships
                            : :comments_articles_article_category_relationships
  where("#{tbl}.user_id = ?", user.id)
}

这样做可以得到你建议的@comment.article_categories.related_to(@current_user, :article)。但我同意Max Williams的观点。这样做没有任何实际收益,只会使你的代码变得不必要地混乱。

如果你真的很想进一步混淆你的代码,你可以这样做:

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

请注意,我认为您的关联存在几个拼写错误。可能应该是这样的:
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接