37

ユーザーモデルのインスタンスにカスタムエラーを追加しようとしていますが、validを呼び出すとどうなりますか?カスタムエラーを消去してtrueを返します。

[99] pry(main)> u.email = "test@test.com"
"test@test.com"

[100] pry(main)> u.status = 1
1

[101] pry(main)> u.valid?
true

[102] pry(main)> u.errors.add(:status, "must be YES or NO")
[
    [0] "must be YES or NO"
]

[103] pry(main)> u.errors
#<ActiveModel::Errors:[...]@messages={:status=>["must be YES or NO"]}>

[104] pry(main)> u.valid?
true

[105] pry(main)> u.errors
#<ActiveModel::Errors:[...]@messages={}>

validateモデル内からメソッドを使用すると機能しますが、この特定の検証は別のメソッド内から追加されています(パラメーターを渡す必要があります)。

User

def do_something_with(arg1, arg2)
  errors.add(:field, "etc") if arg1 != arg2
end

上記の理由で、user.valid?そのエラーがインスタンスに追加された場合でも、はtrueを返します。

4

5 に答える 5

52

ActiveModelでは、valid?次のように定義されます。

def valid?(context = nil)
  current_context, self.validation_context = validation_context, context
  errors.clear
  run_validations!
ensure
  self.validation_context = current_context
end

したがって、既存のエラーはクリアされることが期待されます。すべてのカスタム検証をいくつかのvalidateコールバックに入れる必要があります。このような:

validate :check_status

def check_status
  errors.add(:status, "must be YES or NO") unless ['YES', 'NO'].include?(status)
end
于 2012-12-14T14:05:47.663 に答える
2

モデルにエラーを表示させたい場合は、次のような汚いことを行うことができます。

your_object = YourModel.new 
your_object.add(:your_field, "your message")
your_object.define_singleton_method(:valid?) { false }
# later on...
your_object.valid?
# => false
your_object.errors
# => {:your_field =>["your message"]} 

このdefine_singleton_methodメソッドは、動作をオーバーライドできます.valid?

于 2017-06-01T08:12:46.943 に答える
0

これは、提供されている検証/フレームワークを使用するための代替ではありません。ただし、一部の例外的なシナリオでは、errdモデルを正常に返す必要があります。私は他の選択肢が不可能な場合にのみこれを使用します。このアプローチを使用しなければならなかった数少ないシナリオの1つは、作成の一部が失敗するモデルを作成するサービスオブジェクトの内部です(依存エンティティの解決など)。ドメインモデルがこのタイプの検証を担当することは意味がないため、そこに保存しません(これが、サービスオブジェクトが最初に作成を行う理由です)。ただし、API設計を簡単にするために、「関連付けられたエンティティfooが見つかりません」などのドメインエラーをハングさせ、通常のレール422/処理不可能なエンティティフローを介して戻ると便利な場合があります。

class ModelWithErrors
  def self.new(*errors)
    Module.new do
      define_method(:valid?) { false }
      define_method(:invalid?) { true }
      define_method(:errors) do
        errors.each_slice(2).with_object(ActiveModel::Errors.new(self)) do |(name, message), errs|
          errs.add(name, message)
        end
      end
    end
  end
end

使用some_instance.extend(ModelWithErrors.new(:name, "is gibberish", :height, "is nonsense")

于 2018-08-10T17:54:55.960 に答える
0

新しい懸念を作成する

app / models / concerns / static_error.rb

module StaticError
  extend ActiveSupport::Concern

  included do
    validate :check_static_errors
  end

  def add_static_error(*args)
    @static_errors = [] if @static_errors.nil?
    @static_errors << args

    true
  end

  def clear_static_error
    @static_errors = nil
  end

  private

  def check_static_errors
    @static_errors&.each do |error|
      errors.add(*error)
    end
  end
end

モデルを含める

class Model < ApplicationRecord
  include StaticError
end
model = Model.new
model.add_static_error(:base, "STATIC ERROR")
model.valid? #=> false
model.errors.messages #=> {:base=>["STATIC ERROR"]}
于 2019-06-22T03:23:02.197 に答える
-1

ニーズを達成するためのクリーンな方法はコンテキストですが、迅速な修正が必要な場合は、次のようにしてください。

#in your model
attr_accessor :with_foo_validation
validate :foo_validation, if: :with_foo_validation

def foo_validation
  #code 
end

#where you need it
your_object.with_foo_validation = true
your_object.valid?
于 2012-12-14T13:55:29.543 に答える