我正在使用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
在上面的代码中,where('articles.title LIKE ?', "%#{search}%")
子句重复两次,因此我认为可以使用DRY原则对其进行改进:是否可以使用 Article.search_by_title
< em>方法直接在 ArticleAssociation.search_by_article_title
方法?
典型用例是:
ArticleAssociation.search_by_article_title("Sample string")
Article.search_by_title("Sample string")
答案 0 :(得分:2)
除非你完全改变代码结构,否则不行。
你可以用lambdas做一些黑客攻击,但那会比你正在干的代码更多的代码。有一个好的重构,以及糟糕的重构。除非在2个或更多位置使用非常复杂或长代码,否则您可以担心重构。代码约定很重要,但是对于很小的单方法调用这样的东西是浪费,可能会使你的代码更加神秘。
虽然,我知道当人们不回答你的问题时很烦人,所以在这里:
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
这只是将lambda作为一个常量,对指定对象执行where
调用。两种方法都只包装lambda。
注意:虽然这可能被认为更优雅,但它会大大降低性能,因为lambda,闭包和额外的调用在像Ruby这样的动态语言中很昂贵。但我不认为这对你来说是一个问题。
答案 1 :(得分:1)
根据OP请求,我使用模块发布了我为3模块搜索编写的代码:
module Listable
extend ActiveSupport::Concern
module ClassMethods
# Search a listable module search in properties (or related) tables
def search_from_properties(string)
return where({}) if string.blank?
associations = self.reflect_on_all_associations.map(&:name) &
[:property, :properties, :supplier, :suppliers, :address]
s = "%#{string}%"
associations.inject(self, :includes).where(
((Address[:base] =~ s) | (Address[:city] =~ s)) |
((Property[:owner] =~ s) | (Property[:cif] =~ s)) |
((Supplier[:cups] =~ s) | (Supplier[:contract] =~ s))
)
end
end
end
现在只需将此模块包含在相关类中:
class Property < ActiveRecord::Base
include Listable
end
注意:所有模型都定义了与其他模型相关联的关联(这就是joins
工作的原因)。此外,它使用this wrapper over AR。