如何在两个不同的类中使用DRY范围方法?

Bac*_*cko 5 ruby refactoring ruby-on-rails dry ruby-on-rails-3

我正在使用Ruby on Rails 3.2.2,我想通过"指定"/"过滤"这些关联对象上的属性值来检索/范围关联对象.也就是说,此时我正在使用以下代码:

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
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,该where('articles.title LIKE ?', "%#{search}%")子句重复了两次,因此我认为可以使用DRY原则对其进行改进:是否可以 Article.search_by_title 直接在 方法中使用ArticleAssociation.search_by_article_title 方法?


典型用例是:

  • ArticleAssociation.search_by_article_title("Sample string")
  • Article.search_by_title("Sample string")

Lin*_*ios 2

除非你完全改变代码结构,否则不会。

您可以使用 lambda 进行一些修改,但这会比您正在干燥的代码更多。重构有好的重构之分,也有糟糕的重构之分。除非一段非常复杂或很长的代码在两个或更多地方使用,否则您可以担心重构。代码约定很重要,但对于像这样的微小的单一方法调用的事情来说,这是一种浪费,并且可能会使您的代码更加神秘。

不过,我知道当人们不回答你的问题时会很烦人,所以这里:

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
Run Code Online (Sandbox Code Playgroud)

这只是使 lambda 成为where对指定对象执行调用的常量。这两种方法都只是包装该 lambda。

注意:虽然这可能被认为更优雅,但它会大大降低性能,因为 lambda、闭包和额外的调用在像 Ruby 这样的动态语言中是昂贵的。但我认为这对你来说不是问题。