2017-05-08 15 views
1

以下のコードは列挙型を使用する多態性モデルの単純化されたバージョンですが、検証には苦労しています。Railsの列挙の検証に失敗しました

モデルの最後の行は問題の検証です。

これは動作します:

validates_inclusion_of :value, in: Vote.values.keys 

これがエラーを返す動作しません:

validates_inclusion_of :value, in: vote_options.keys 

エラー

ActiveRecord::RecordInvalid: Validation failed: Value is not included in the list 

モデル:

class Vote < ApplicationRecord 
    belongs_to :voteable, polymorphic: true 

    vote_options = {vote_no: 0, vote_yes: 1} 
    enum value: vote_options 

    validates_inclusion_of :value, in: vote_options.keys 
end 

更新:

class Vote < ApplicationRecord 
    belongs_to :voteable, polymorphic: true 

    VOTE_OPTIONS = HashWithIndifferentAccess.new({ vote_no: 0, vote_yes: 1 }).freeze 
    EMOJI_OPTIONS = HashWithIndifferentAccess.new({thumb_up: 2, thumb_down: 3, happy_face: 4, sad_face: 5}).freeze 

    enum value: HashWithIndifferentAccess.new.merge(VOTE_OPTIONS).merge(EMOJI_OPTIONS) 

    validates_inclusion_of :value, in: vote_options.keys 
end 

アップデート2:

class Like < ApplicationRecord 
    belongs_to :likeable, polymorphic: true 

    VOTE_OPTIONS = { vote_no: 0, vote_yes: 1 }.freeze 
    EMOJI_OPTIONS = { thumb_up: 2, thumb_down: 3, happy_face: 4, sad_face: 5 }.freeze 

    enum value: VOTE_OPTIONS.merge(EMOJI_OPTIONS) 

    with_options :if => :is_meeting? do |o| 
     o.validates_uniqueness_of :user_id, scope: [:likeable_id, :likeable_type], message: "You have already voted on this item." 
     o.validates_inclusion_of :value, in: HashWithIndifferentAccess.new(VOTE_OPTIONS).keys 
    end 

    with_options :if => :is_comment? do |o| 
     o.validates_uniqueness_of :user_id, scope: [:likeable_id, :likeable_type], message: "You can only tag once." 
     o.validates_inclusion_of :value, in: HashWithIndifferentAccess.new(EMOJI_OPTIONS).keys 
    end 

    def is_meeting? 
     self.likeable_type == "Meeting" 
    end 

    def is_comment? 
     self.likeable_type == "Comment" 
    end 

end 

答えて

0

この現象の理由はenumconvertsが渡されたことをハッシュHashWithIndifferentAccessにあります。これは、通常のハッシュに対する特別なActiveSupport拡張であり、はそのシンボルと文字列キーを同じとして扱います。

は今、あなたのvote_options定義はシンボルを使用しますが、レコード属性をDBへの列挙値を設定する際のActiveRecordは内部文字列を使用しています。 Vote.values.keysバリアントでレコードを検証すると、Vote.valuesはの定義で作成されたの定義で作成されたハッシュを返すため、文字列値(属性内の)と列挙型のシンボルキーを比較してもすべて機能します。

逆に、検証にvote_options.keysを使用すると、文字列の値とシンボルを比較するため、Rubyでは同じものではないため失敗します。無関心なアクセスをハッシュを使用し、これを克服し、今でも(実際には、私が代わりにここに凍結定数をお勧めしたい)クラス変数を使用し、

すぎ

VOTE_OPTIONS = HashWithIndifferentAccess.new({ vote_no: 0, vote_yes: 1 }).freeze 
enum value: VOTE_OPTIONS 

validates_inclusion_of :value, in: VOTE_OPTIONS.keys 

更新 - 複数のマージ実際に必要な場所にHashWithIndifferentAccessを宣言するだけで、他の場所で単純なハッシュを使うことができます:

VOTE_OPTIONS = { vote_no: 0, vote_yes: 1 }.freeze 
EMOJI_OPTIONS = { thumb_up: 2, thumb_down: 3, happy_face: 4, sad_face: 5 }.freeze 

enum value: VOTE_OPTIONS.merge(EMOJI_OPTIONS) 

validates_inclusion_of :value, in: HashWithIndifferentAccess.new(VOTE_OPTIONS).keys 
+0

マージメソッドを使う正しい方法はありますか? https://apidock.com/rails/v4.2.7/ActiveSupport/HashWithIndifferentAccess/merge – Dercni

+0

一般的にはいですが、ハッシュ宣言とマージのIMOよりわかりやすい提案に関する私の更新された回答を参照してください。また、値がある列挙型が必要な理由がわかりません。そのうちのいくつかは無効ですか? (注:私の最初の例では、属性名を修正しました。) – BoraMa

+0

値のないenumを使用すると、順序が暗黙的であるため問題が発生する可能性があることを理解しています。どちらが無効ですか? – Dercni

関連する問題