web-dev-qa-db-ja.com

Rails配列の値を検証しています

私のスケジュールモデルでは、int []である:wdaysフィールドに検証を追加したいと思います。値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 }

しかしどちらも機能しません

モデルの配列の値を検証する適切な方法は何ですか?

22
bsiddiqui

デフォルトの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
26
mechanicalfish

既存のRails検証構造内でこれを処理する簡単な方法があるかどうかはわかりません。バリデーターが実際に処理するように構築されていないという奇妙なケースがあります。このような何かのためのカスタムバリデーターを書くには(既存のバリデーション拡張ジェムが利用できないと仮定して)次のようなもの:

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
5
Paul Richter

私はこの宝石を作成しました: 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

楽しい!コメント、プルリクエスト、フィードバックはいつでも歓迎です。

0
Rafael Biriba

私の意見では、受け入れられた回答は実際には正しくこれを行いませんでした。誰かがwdays = 'meow'を設定すると、警告なしで空の配列wdays == []に設定されます。

そのメソッドでwdaysを要求すると、型キャストが発生します。無効な場合、データはすでに配列に変換されています。

タイプをチェックするときは、wdaysの代わりにwdays_before_type_castを使用する必要があります。

_ 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
0
Arian Faurtosh