の除去、またはオーバーライドするActiveRecordの検証を追加"スーパークラスはmixin
-
22-09-2019 - |
質問
私が使っている通関のための認証を私のレールに願います。の Clearance::User
mixinを追加しカップルの検証によっ User
モデルが表示されていただきたい削除、またはオーバーライド.には、どうするのがベストなの?
の検証であるという
validates_uniqueness_of :email, :case_sensitive => false
これ自体は悪くないがっていなければいけないと考えて追加 :scope => :account_id
.問題は場合を追加することを私 User
モデル
validates_uniqueness_of :email, :scope => :account_id
を取得しま 両 検証により、隙間追加しより厳しい方のように鉱山にしても、何の効果もありません。いることを、確認する必要がありみ鉱山運行しています。いるのか?
解決 2
当社が"解決"の問題点は以下のhack:
- みエラーの
:email
属性の型:taken
- 確認のメールはこのアカウントの検証したい)
- 削除し、エラーの場合はメールには、よりいます。
音声合理的なまでの読み込みコードの見かに削除します。 ActiveRecord::Errors
のない方法で除去の誤差回数を増加さを鷲掴みにしたので炉内構造物です。スーパー duperメガ醜い.
このコード:
def validate
super
remove_spurious_email_taken_error!(errors)
end
def remove_spurious_email_taken_error!(errors)
errors.each_error do |attribute, error|
if error.attribute == :email && error.type == :taken && email_unique_for_account?
errors_hash = errors.instance_variable_get(:@errors)
if Array == errors_hash[attribute] && errors_hash[attribute].size > 1
errors_hash[attribute].delete_at(errors_hash[attribute].index(error))
else
errors_hash.delete(attribute)
end
end
end
end
def email_unique_for_account?
match = account.users.find_by_email(email)
match.nil? or match == self
end
誰もが知って、より良いるのですが、非常に感謝しています。
他のヒント
私はGEMをフォークして、上書きすることができる簡単なチェックを追加したいです。私の例では、懸念を使用します。
懸念ます:
module Slugify
extend ActiveSupport::Concern
included do
validates :slug, uniqueness: true, unless: :skip_uniqueness?
end
protected
def skip_uniqueness?
false
end
end
モデル:
class Category < ActiveRecord::Base
include Slugify
belongs_to :section
validates :slug, uniqueness: { scope: :section_id }
protected
def skip_uniqueness?
true
end
end
私は最近、この問題を持っていたし、Googleは私に答えを与えなかった後に迅速に十分な私は、この問題に対するすっきり依然として非理想的なソリューションを見つけました。今では、あなたの使用して、既存のスーパークラスだと、これはあなたのケースでは必ずしも動作しますが、私はちょうど使用して私のためにそれは私自身のコードだった:。もしスーパークラスの型チェックとのparam
def SuperClass
validates_such_and_such_of :attr, :options => :whatever, :if => Proc.new{|obj| !(obj.is_a? SubClass)}
end
def SubClass < SuperClass
validates_such_and_such_of :attr
end
multpileサブクラスの場合には、
def SuperClass
validates_such_and_such_of :attr, :options => :whatever, :if => Proc.new{|obj| [SubClass1, SubClass2].select{|sub| obj.is_a? sub}.empty?}
end
def SubClass1 < SuperClass
validates_such_and_such_of :attr
end
def SubClass2 < SuperClass
end
私はシュプレー製品財産:value
の検証を削除するために必要な、Klass.class_eval
とclear_validators!
のAciveRecord::Base
とsimplierソリューションがありますようです。
module Spree
class ProductProperty < Spree::Base
#spree logic
validates :property, presence: true
validates :value, length: { maximum: 255 }
#spree logic
end
end
そして、ここでそれを上書き
Spree::ProductProperty.class_eval do
clear_validators!
validates :property, presence: true
end
私はゲームに遅刻知っているが、方法について:
module Clearance
module User
module Validations
extend ActiveSupport::Concern
included do
validates :email,
email: true,
presence: true,
uniqueness: { scope: :account, allow_blank: true },
unless: :email_optional?
validates :password, presence: true, unless: :password_optional?
end
end
end
end
イニシャライザで
Errors.delete(キー)属性のすべてのエラーを削除し、私は唯一の属性に属するエラーの特定のタイプを削除したいです。この次のメソッドは、すべてのモデルに追加することができます。
削除、nilの場合は、それ以外の場合は、メッセージを返します。エラーを除去した後、予想通り、他のすべてのメソッドが動作するはずですので、内部データ構造が変更されています。
メソッド検証した後、モデルからの誤差を除去するためには、実行されています。
def remove_error!(attribute, message = :invalid, options = {})
# -- Same code as private method ActiveModel::Errors.normalize_message(attribute, message, options).
callbacks_options = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
case message
when Symbol
message = self.errors.generate_message(attribute, message, options.except(*callbacks_options))
when Proc
message = message.call
else
message = message
end
# -- end block
# -- Delete message - based on ActiveModel::Errors.added?(attribute, message = :invalid, options = {}).
message = self.errors[attribute].delete(message) rescue nil
# -- Delete attribute from errors if message array is empty.
self.errors.messages.delete(attribute) if !self.errors.messages[attribute].present?
return message
end
使用方法:
user.remove_error!(:email, :taken)
メソッドは、指定された属性とメッセージを除く有効性を確認する。
def valid_except?(except={})
self.valid?
# -- Use this to call valid? for superclass if self.valid? is overridden.
# self.class.superclass.instance_method(:valid?).bind(self).call
except.each do |attribute, message|
if message.present?
remove_error!(attribute, message)
else
self.errors.delete(attribute)
end
end
!self.errors.present?
end
使用方法:
user.valid_except?({email: :blank})
user.valid_except?({email: "can't be blank"})
でのRails 4、あなたはのHAVE の便利な名前の検証方法ならば... skip_callback(:validate, :name_of_validation_method)
を使用することができるはずです。 の(免責事項:私はそれをテストしていません)のない場合、あなたはスキップしたいものを見つけるためにコールバックのリストにハッキングし、そのfilter
オブジェクトを使用する必要があります。
の例:の
私は2.1.4からアップグレードシュプレーを持つ、Railsの4.1.11とシュプレー2.4.11.betaを使用してサイトに取り組んでいます。我々のコードを格納歴史的目的のための1つのテーブル内Spree::Variant
sの複数のコピー、
アップグレードので、今validates_uniqueness_of :sku, allow_blank: true, conditions: -> { where(deleted_at: nil) }
宝石、我々のコードを壊しています。あなたが気づくように、しかし、それはそうするという名前のメソッドを使用していません。これは私がSpree::Variant.class_eval
ブロックに何をやったかです。
unique_sku_filter = _validate_callbacks.find do |c|
c.filter.is_a?(ActiveRecord::Validations::UniquenessValidator) &&
c.filter.instance_variable_get(:@attributes) == [:sku]
end.filter
skip_callback(:validate, unique_sku_filter)
この表示されますが、完全にVariant
のチェーンからのコールバックを削除します。
NB。それはそれへのアクセサを持っていないので、私は、instance_variable_get
ため@attributes
を使用しなければなりませんでした。あなたは同様にc.filter.options
ブロックにfind
を確認することができます。上記の例では、このようになります:
c.filter.options
#=> {:case_sensitive=>true, :allow_blank=>true, :conditions=>#<Proc:... (lambda)>}
ここでは私のために働いたのRails 3「ソリューション」だ(誰もがそれを提供してくださいより良い方法を持っている場合は、再度は!)
class NameUniqueForTypeValidator < ActiveModel::Validator
def validate(record)
remove_name_taken_error!(record)
end
def remove_name_taken_error!(record)
errors = record.errors
errors.each do |attribute, error|
if attribute == :name && error.include?("taken") && record.name_unique_for_type?
errors.messages[attribute].each do |msg|
errors.messages[attribute].delete_at(errors.messages[attribute].index(msg)) if msg.include?("taken")
end
errors.messages.delete(attribute) if errors.messages[attribute].empty?
end
end
end
end
ActsAsTaggableOn::Tag.class_eval do
validates_with NameUniqueForTypeValidator
def name_unique_for_type?
!ActsAsTaggableOn::Tag.where(:name => name, :type => type).exists?
end
end
は十分でした。私が検証するために郵便番号を望んでいない。
after_validation :remove_nonrequired
def remove_nonrequired
errors.messages.delete(:zipcode)
end