2012-01-26 1 views
2

は、このモデルを与えられた:それはactive?方法で条件を繰り返さないため 他の方法でレール範囲条件を再利用するためのDRYソリューション? Railsの3.1に

class Subscripion < ActiveRecord::Base 
    scope :active, lambda { 
     where("start_date is not ? AND end_date >= ?", nil, Date.today) 
    } 

    def active? 
     self.class.active.exists?(self) 
    end 
end 

はこれまでのところ、これは、私は考えることができ、乾燥-estのソリューションです。

2つの欠点は、しかしあります

  • は、サブスクリプションのインスタンスを考えると、何のデータベースクエリは、それがアクティブであるかどうかを決定するために必要ないであろう。その属性に基づいて確認できます:!start_date.nil? && end_date >= Date.todayexists?を呼び出すと、追加のデータベースクエリが発生します。
  • exists?スコープのexists?を呼び出す前に最初のサブスクリプションインスタンスを変更した場合、exists?はインスタンスを無視してデータベースに直接クエリを実行するので、結果は必要ではありません。

さらに良いソリューションについてのアイデアは、1つの場所で条件を定義していますか?

答えて

1

私はアクティブだと思いますか?メソッドの実装は、すべてのアクティブなサブスクリプションをロードし、次に自己のリストを調べるため、適切ではありません。より良いアプローチは次のようなものです:

def active? 
    self.class.active.where(id: self.id).present? 
end 

この実装は、COUNTクエリでデータベースをチェックします。

いずれにしても、私はそれがアクティブな方にとって理にかなっていると思いますか? (!start_date.nil?& & end_date> = Date.today)。これは、現在のインスタンスの実際のステータスを反映する唯一の方法であるためです。

+0

提案しているように 'where(id:self.id).present? 'を使うのはやや効率的ですが、唯一の違いは結果の行のすべての属性ではなく、カウントを返すことです。 '存在しますか?(自己)'はすべてのアクティブなサブスクリプションを最初にロードしません。 'SELECT COUNT(*)'の代わりに 'SELECT 1 FROM ... LIMIT 1'というクエリを出すという点を除いて、ほとんど同じクエリを実行します。 私は、 '!start_date.nil? && end_date> = Date.today'は 'active?'メソッドにとって最も正しいですが、スコープに対して同じ条件を2回定義します。これは、将来エラーが発生しやすくなります。 –