25

在我的 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

4 回答 4

28

我认为默认的 Rails 验证器不会在这里解决问题,但您可以这样做:

validate :validate_wdays

def validate_wdays
  if !wdays.is_a?(Array) || wdays.any?{|d| !(0..6).include?(d)}
    errors.add(:wdays, :invalid)
  end
end
于 2013-11-11T18:05:45.510 回答
8

我不确定在现有的 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
于 2013-11-11T18:07:51.953 回答
2

我创建了这个宝石: 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

享受!评论、拉取请求和反馈总是受欢迎的。

于 2017-06-02T08:07:50.970 回答
1

在我看来,接受的答案并没有真正正确地做到这一点。如果有人设置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
于 2019-11-21T01:51:00.453 回答