【问题标题】:Rails enum validation failingRails 枚举验证失败
【发布时间】:2017-05-08 05:00:46
【问题描述】:

下面的代码是使用枚举的多态模型的简化版本,但我正在努力验证。

模型的最后一行是问题验证。

这行得通:

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

【问题讨论】:

    标签: ruby-on-rails validation enums


    【解决方案1】:

    出现这种行为的原因是 enum converts 将传入的哈希值转换为 HashWithIndifferentAccess。这是对普通哈希的特殊 ActiveSupport 扩展,将其符号和字符串键视为相同

    现在,您的vote_options 定义使用符号,但ActiveRecord 在内部在将枚举值 设置为数据库记录属性时使用字符串。当使用 Vote.values.keys 变体验证记录时,即使它将字符串值(在属性中)与枚举定义中的符号键进行比较,它也能正常工作,因为 Vote.values 将返回具有无关访问的 hash enum 定义中创建。

    相反,如果您使用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
    

    【讨论】:

    • 我的更新是使用合并方法的正确方法吗? apidock.com/rails/v4.2.7/ActiveSupport/…
    • 通常是的,但请参阅我的更新答案以获得 IMO 更易读的哈希声明和合并建议。另外,我不清楚为什么你需要一个带有值的枚举,其中一些是无效的? (注意:在我的第一个示例中也修复了属性名称。)
    • 我知道使用没有值的枚举会导致问题,因为顺序是隐式的,如果添加新值则无法更改。哪些无效?
    • 不,抱歉,应该更明确一点,我只是想知道为什么您只针对可以在 enun 属性中的所有值的子集(投票选项)进行验证?
    • 我正在尝试对投票和喜欢使用相同的多态模型的想法,因此可用选项的验证将取决于相关模型。不相信我不应该只为每个目的使用一个单独的模型,因为你可能有 5 个函数,我在上面的 update2 中只显示了 2 个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    • 2015-06-29
    • 2010-09-06
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多