2012-04-19 10 views
1

カスタムスコープまたは仮想スコープで属性の一意性を検証するにはどうすればよいですか?私は仮想属性を使用することを考えましたが、データベースのaudit_yearを照会しようとしています。私はむしろ、この一意制約の目的のためだけに別のデータベース列を作成しません。仮想属性スコープでRailsモデル属性の一意性を検証する方法

各場所では1年に1回の監査しかスケジュールされていないため、スケジュールされた属性から年を抽出し、その範囲で一意性を検証する必要があります。

class Audit 
    attr_accessible :location_name, :scheduled_date, :completion_date ... 

    validates :location_name, :presence => true, :uniqueness => { :scope => :audit_year } 

    ... 

    def audit_year 
     scheduled_date.year 
    end 

end 

私の仮想属性の試行では正しいパスにさえいないかもしれません。レールでこれを行う「正しい」方法は何でしょうか?

答えて

0

私はこれがちょっと遅かったと知っていますが、私はピッチをとっていると思いました。私はこれをメモリからやっているので、これにちょっとぶつかる必要があります。

私の最初の考えはあなたのaudit_yearメソッドにあります。あなたは何年もデータベースをクエリできます。次のようなものがあります。

def audit_year 
    !self.class.select('selected_date').map{ |a| a.selected_date.year }.include?(selected_date.year) 
    # or using Rails 3.2 and Ruby 1.9.3: 
    # !self.class.pluck('created_at').map(&:year).include?(selected_date.year) 
end 

私が一意の方法を仮定すると、偽を返した場合、検証は失敗します。このコードでは、クラスからその1つの列だけを選択します(私は、監査の代わりにself.classを使用して再利用可能です)。その後、年を配列にマップします。それが含まれている(真)場合は、反対(!)を返します。あなたはおそらくuniqでクエリを最適化することができますが、必要か否かに応じてテーブルの大きさによって異なります。

もう1つの方法は、実際にそれほど難しくない属性の独自のバリデータをロールすることです。唯一の違いは、上記に加えて条件付きでselected_date.present?をチェックする行を追加することです。大きなリソースは、コールバックやエラーのためのRailsガイドです。あなたがどのように分かっているのかわからない場合は、http://guides.rubyonrails.org/active_record_validations_callbacks.html

希望します。