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