私のスケジュールモデルでは、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 }
しかしどちらも機能しません
モデルの配列の値を検証する適切な方法は何ですか?
デフォルトの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
既存の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
私はこの宝石を作成しました: 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
楽しい!コメント、プルリクエスト、フィードバックはいつでも歓迎です。
私の意見では、受け入れられた回答は実際には正しくこれを行いませんでした。誰かが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