5

私の User モデルでは、email、first_name、last_name、password などの通常の容疑者がいます。

すべてまたは一部の検証をスキップする必要がある場合がいくつかあります。

現在、次のような条件を除きます。

  validates :first_name, presence: :true, etc..., unless: :skip_first_name_validation?
  validates :last_name, presence: :true, etc..., unless: :skip_last_name_validation?
  validates :email, presence: :true, etc..., unless: :skip_email_validation?

もちろん、私も持っています:

  attr_accessor :skip_first_name_validation, :skip_last_name_validation, etc.

次に、プライベート メソッドを使用してそれぞれの状態を確認します。

  def skip_first_name_validation?
    skip_first_name_validation
  end

  def skip_last_name_validation?
    skip_last_name_validation
  end

  def skip_email_validation?
    skip_email_validation
  end

  etc..

trueそこから、検証をスキップする必要があるときはいつでも、コントローラーでこれらの各人に値を割り当てるだけです。


これはすべて正常に機能しますが、もっとエレガントな方法があるかどうか疑問に思っていますか?

モデルの各属性に対して、次のような単純な条件を使用できれば理想的です。

:skip_validation?

私のコントローラーでは、次のようにします。

skip_validation(:first_name, :last_name, :password) = true

これをどのようにプログラムするかについて誰かが提案できますか? 既存の宝石/ライブラリを使用したくないのですが、レールでこの動作をプログラムする方法を理解しようとしています。ありがとう。

4

2 に答える 2

1

これは、すべてのセッターとチェッカーを動的に定義するのに役立ちます

private 
def self.skip_validations_for(*args)
  
  # this block dynamically defines a setter method 'set_validations' 
  # e.g.
  #   set_validations(true, :email, :last_name, :first_name)
  #   set_validations(false, :email, :last_name, :first_name)
  define_method('set_validations') do |value, *params|
    params.each do |var|
      self.send("skip_#{var.to_s}_validations=", value)
    end
  end

  # this block walks through the passed in fields and defines a checker
  # method `skip_[field_name]_validation?
  args.each do |arg|
    if self.method_defined? arg
      send :define_method, "skip_#{attr.to_s}_validation?" do 
        send "skip_#{attr.to_s}_validation"  
      end
    end
  end
end

次に、これがクラスにネイティブであるか、モジュールを介して含まれているかに関係なく、モデルに次を追加できます。

Class Foo < ActiveRecord::Base
  validate :bar, :presence => true
  validate :baz, :length_of => 10

  skip_validations_for :bar, :baz
end

どの時点でアクセスできますか

set_validations(true, :bar, :baz)

skip_bar_validation? 

アップデート:

このコードはどこに行くのでしょうか?

これは、使用する範囲によって異なります。1 つのモデルで検証をオーバーライドするだけの場合は、すべてをそのモデルに直接配置できます。ただしModule、すべてのクラスでこれを実行できる を作成する場合は、ディレクトリModuleに putを作成し、それがロード パスにあることを確認する必要があります。lib/おそらく、これはそれであなたを助けることができます.

なぜこれほど劇的に変化したのでしょうか。

もともと私はインスタンスで _validations メソッドを使用していましたが、これは検証のハッシュを返す ActiveRecord メソッドです (フィールド名 -> ActiveRecord::Validation)。そのやり方は、自動的にすべてのフィールドの能力をオンにしました。必要な特定のフィールドを選択できるようにする方が、Rails らしいです。

于 2012-05-04T14:16:36.460 に答える
0

私はメタプログラミングの専門家ではありませんが、このように実装できると思います。

class User < ActiveRecord::Base
  ...
  %w(email first_name last_name).each do |attr|
    self.send :attr_accessor, "skip_#{attr}_validation".to_sym
    self.send :alias, "skip_#{attr}_validation?".to_sym, "skip_#{attr}_validation".to_sym
    self.send :validates_presence_of, attr, { unless: "skip_#{attr}_validation?".to_sym }
  end

  def skip_validation_for(*attrs)
    attrs.map{|attr| send "skip_#{attr}_validation=", true }
  end
end

モデルに組み込むのはあまりエレガントではありませんが、モジュールにすることができます。使用方法は次のようになります。

class User < ActiveRecord::Base
  include SkipValidations
  skip_validations :email, :first_name, :last_name
end
于 2012-05-04T14:10:29.507 に答える