2012-06-05 16 views
5

私はRuby on Rails 3.2.2を使用していますが、これらの関連オブジェクトの属性値を「指定」/「フィルタリング」することで、スコープ関連のオブジェクトを取得したいと思います。上記のコードで2つの異なるクラスで使用されるスコープメソッドをどのようにDRYするのですか?

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}%")句を2回繰り返しているので、私はそれはDRY原則を向上させることができることを考えた:つまり、この時点で私は、次のコードを使用しています、ですはそれを使用することが可能ですArticle.search_by_title方法に直接ArticleAssociation.search_by_article_titleの方法では?


典型的な使用例は以下のとおりです。

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

私はこの同じ状況(4つの関連モデル)に直面し、一般的な検索方法を保持するモジュールを作成しました。 Utはあなたの求めるものではありませんが、典型的な解決策です。 – tokland

+0

クラス間で共有されるコードは、普通はモジュール – apneadiving

+0

で終了しますが、squeelのシフターはこれに使用できますが、ARの代わりにsqueelを使うことは大きな変更です.. https://github.com/ernie/squeel#sifters – tokland

答えて

2

あなたがいない、完全にコードの構造を変更しない限り。

ラムダでハッキングを行うこともできますが、それはコードを作成してからDRYすることになります。良いリファクタリングや悪いリファクタリングなどがあります。 非常に複雑なコードまたは長いコードが2つ以上の場所で使用されていない限り、リファクタリングについて心配する必要はありません。コードの規則は重要ですが、小さな1メソッド呼び出しの場合、そのようなものは無駄であり、おそらくコードをよりわかりにくくするでしょう。

けれども、私は人々がここに、あなたの質問に答えていないとき、それは迷惑なんだということを知っている:

だけ指定されたオブジェクトに where呼び出しを実行定数としてラムダを作る
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 

。どちらのメソッドもラムダをラップします。

注:Rubyのような動的言語では、lambdas、closure、および余分な呼び出しが高価であるため、これはよりエレガントであると考えられますが、パフォーマンスが大幅に低下します。しかし、私はそれがあなたにとって問題だとは思わない。

class Property < ActiveRecord::Base 
    include Listable 
end 

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 

が今だけ関連するクラスでは、このモジュールを含める:

+0

@ Linux_iOS.rb.cpp.c.lisp.n - あなたの答えをありがとう。しかし、私はコード* 'where( 'articles.title LIKE?'、"%#{search}% ")を使う必要がある場所がたくさんあります。私のクラスでコードをどこにでも繰り返すのは悪いですか?* – Backo

+1

@Backo:コードをたくさん使うと、おそらくラムダが良いでしょうアイディア。この例のように2回だけ使用すると、繰り返しの方がよいでしょう。 – Linuxios

1

はOPの要求ごととして、私はモジュールを使用して3-モジュール検索のために書いたコードを投稿します注:すべてのモデルには、他のモデルとの関連付けが定義されています(そのため、joinsが機能します)。また、this wrapper over ARを使用します。

関連する問題