Rails验证数组中的值

时间:2013-11-11 17:51:53

标签: ruby-on-rails ruby postgresql validation activerecord

在我的Schedule模型中,我想在:wdays字段中添加一些验证,这是一个int []。我只希望值0..6有效

有效

Schedule.wdays = [0,1,6]

无效

Schedule.wdays = [0,1,10]

我尝试使用

validates :wdays, inclusion: { in: [0, 1, 2, 3, 4, 5, 6] }

validates :wdays, inclusion: { in: 0..6 }

但不起作用

验证模型中数组中值的正确方法是什么?

4 个答案:

答案 0 :(得分:26)

我不认为默认的Rails验证器会在这里做到这一点,你可以这样做:

validate :validate_wdays

def validate_wdays
  if !wdays.is_a?(Array) || wdays.detect{|d| !(0..6).include?(d)}
    errors.add(:wdays, :invalid)
  end
end

答案 1 :(得分:5)

我不确定在现有的Rails验证结构中是否有更简单的方法来处理这个问题。你有一个奇怪的例子,验证器并没有真正构建来处理。您可能需要为此类内容编写自定义验证程序(假设现有的验证扩展gem不可用)。像这样:

class ArrayInRangeValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, valueArray)
    valueArray.each do |value|
      record.errors.add "#{attribute} - #{value}", (options[:message] || "is not in the acceptable range") unless (1..6).include?(value)
    end
  end
end

然后在你的模型中:

class Schedule < ActiveRecord::Base
    include ActiveModel::Validations

    validates :wdays, :presence => true, :array_in_range => true

    ... other model stuff
end

答案 2 :(得分:0)

我创建了这个gem: https://github.com/rafaelbiriba/active_model_validates_intersection_of

基本上,您可以使用:

class User < ActiveRecord::Base
   DEFAULT_PERMISSION = ["read", "write", "share"]
   validates_intersection_of :permission, in: DEFAULT_PERMISSION
end

如果你尝试:

user = User.new(permission: ["read", "share"])
user.valid? #true

user = User.new(permission: ["read", "admin"])
user.valid? #false

享受!欢迎提出评论,拉取请求和反馈。

答案 3 :(得分:0)

我认为接受的答案并没有真正正确地做到这一点。如果有人设置了wdays = 'meow',它将在没有警告的情况下将其设置为空数组wdays == []

正在使用此方法要求wdays进行类型转换。如果无效,它已经将数据转换成数组。

检查类型时,应使用

wdays_before_type_cast而不是wdays

请参见_before_type_cast

validate :validate_wdays

def validate_wdays
  errors.add(:wdays, :invalid) if wdays_changed? && !wdays_before_type_cast.is_a?(Array)
  errors.add(:wdays, :invalid) if wdays.any? { |d| (0..6).exclude?(d) }
end