简体   繁体   English

Rails枚举验证失败

[英]Rails enum validation failing

The code below is a simplified version of a polymorphic model that uses enums however I am struggling with the validation. 下面的代码是使用枚举的多态模型的简化版本,但我正在努力验证。

The last line of the model is the problem validation. 模型的最后一行是问题验证。

This works: 这有效:

validates_inclusion_of  :value, in: Vote.values.keys

This does not work returning an error: 这不起作用返回错误:

validates_inclusion_of  :value, in: vote_options.keys

Error 错误

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

Model: 模型:

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

Update: 更新:

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: 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

The reason for this behavior is that enum converts the passed-in hash into a HashWithIndifferentAccess . 这种行为的原因是enum 传入的哈希转换为HashWithIndifferentAccess This is a special ActiveSupport extension to a normal Hash that treats its symbol and string keys the same . 这是普通Hash的特殊ActiveSupport扩展, 它将符号和字符串键视为相同

Now, your vote_options definition uses symbols but ActiveRecord internally uses strings when setting enum values to db record attributes. 现在,您的vote_options定义使用符号,但ActiveRecord 在将枚举值设置为db记录属性时在内部使用字符串 When validating the record with the Vote.values.keys variant, it all works even though it is comparing a string value (in the attribute) to a symbol key in the enum definition, because Vote.values will return the hash with indifferent access created in the enum definition. 使用Vote.values.keysVote.values.keys记录时,即使它将字符串值(在属性中)与枚举定义中的符号键进行比较,它仍然有效,因为Vote.values将返回创建了无关访问哈希值enum定义中。

On the contrary, if you use vote_options.keys for your validation, it will fail because it compares string values with symbols and these are not the same things in Ruby. 相反,如果使用vote_options.keys进行验证,它将失败,因为它将字符串值与符号进行比较,这些在Ruby中并不相同。

To overcome this and still use a class variable (actually, I'd suggest a freezed constant instead here), use a hash with indifferent access too : 为了克服这个问题并且仍然使用类变量(实际上,我建议使用冻结常量), 使用具有无差别访问权限的哈希

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

validates_inclusion_of :value, in: VOTE_OPTIONS.keys

Update - multiple merged hashes - you only have to declare a HashWithIndifferentAccess where you actually need it, you can use simple hashes in other places: 更新 - 多个合并哈希 - 您只需在实际需要的地方声明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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM