2017-05-08 148 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 

UPDATE2:

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定義使用符號但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

我知道,使用不帶值的枚舉會導致問題,因爲排序是隱式的,如果添加新值,則無法更改。哪些是無效的? – Dercni