إزالة أو تجاوز التحقق من صحة ActivereCord التي تضاف إليها الطبقة الفائقة أو mixin

StackOverflow https://stackoverflow.com/questions/2309757

سؤال

أنا أستخدم إزالة المصادقة في تطبيق Rails الخاص بي. ال Clearance::User يضيف Mixin بعض عمليات التحقق من صحة إلى User النموذج ، ولكن هناك واحد من هؤلاء أود إزالته أو تجاوزه. ما هي أفضل طريقة للقيام بذلك؟

التحقق من الصحة هو

validates_uniqueness_of :email, :case_sensitive => false

وهو في حد ذاته ليس سيئًا ، لكنني سأحتاج إلى إضافة :scope => :account_id. المشكلة هي أنه إذا أضفت هذا إلى بلدي User نموذج

validates_uniqueness_of :email, :scope => :account_id

انا حصلت على حد سواء عمليات التحقق ، وتضيف التخليص واحد أكثر تقييدًا من لي ، لذلك ليس لي تأثير. أحتاج إلى التأكد من أن لي يدير فقط. كيف أقوم بهذا العمل؟

هل كانت مفيدة؟

المحلول 2

انتهى بي الأمر "حل" المشكلة مع الاختراق التالي:

  1. ابحث عن خطأ في :email سمة من النوع :taken
  2. تحقق مما إذا كان البريد الإلكتروني فريدًا لهذا الحساب (وهو التحقق الذي أردت القيام به)
  3. قم بإزالة الخطأ إذا كان البريد الإلكتروني فريدًا لهذا الحساب.

يبدو معقولًا حتى تقرأ الكود واكتشف كيف أقوم بإزالة خطأ. ActiveRecord::Errors لا يوجد لديه طرق لإضافة الأخطاء بمجرد إضافة ، لذلك يجب أن أمسك بها الداخلية والقيام بذلك بنفسي. سوبر المخادع ميجا قبيح.

هذا هو الرمز:

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

إذا كان أي شخص يعرف طريقة أفضل ، فسأكون ممتنًا جدًا.

نصائح أخرى

كنت أتخلى عن الأحجار الكريمة وأضيف شيكًا بسيطًا ، يمكن بعد ذلك تجاوزه. مثالي يستخدم مصدر قلق.

الاهتمام:

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 الإجابات بسرعة كافية ، وجدت حلاً غير مألوف ولكن لا يزال غير مثالي لهذه المشكلة. الآن لن يعمل هذا بالضرورة في حالتك حيث يبدو أنك تستخدم فصولًا فائقة موجودة مسبقًا ، لكن بالنسبة لي كان هذا الكود الخاص بي ، لذا فقد استخدمت للتو: إذا كان بارام مع نوع تحقق من الفئة الفائقة.

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

في حالة الطبقات الفرعية متعددة البديل

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

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

في مُهيئ؟

الأخطاء. delete (مفتاح) يزيل جميع الأخطاء لسمة وأريد فقط إزالة نوع محدد من الخطأ الذي ينتمي إلى سمة. يمكن إضافة هذه الطريقة التالية إلى أي نموذج.

إرجاع الرسالة إذا تمت إزالتها ، على خلاف ذلك. يتم تعديل هياكل البيانات الداخلية بحيث يجب أن تعمل جميع الطرق الأخرى كما هو متوقع بعد إزالة الخطأ.

صدر تحت ترخيص معهد ماساتشوستس للتكنولوجيا

طريقة لإزالة الخطأ من النموذج بعد تشغيل عمليات التحقق.

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 ، يجب أن تكون قادرًا على الاستخدام skip_callback(:validate, :name_of_validation_method)... اذا أنت لديك طريقة التحقق من صحة مريحة. (إخلاء المسئولية: لم أختبر ذلك.) إذا لم يكن الأمر كذلك ، فستحتاج إلى اختراق قائمة عمليات الاسترجاعات للعثور على تلك التي تريد تخطيها ، واستخدامها filter هدف.

مثال:

أنا أعمل على موقع باستخدام Rails 4.1.11 و Spree 2.4.11.beta ، بعد ترقية فورة من 2.1.4. يخزن الكود لدينا نسخ متعددة من Spree::VariantS في طاولة واحدة ، لأغراض تاريخية.

منذ الترقية ، الجوهرة الآن 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

بالنسبة لي على الرمز الناري أدناه كان كافيًا. لا أريد التحقق من صحة zipcode.

after_validation :remove_nonrequired

def remove_nonrequired
  errors.messages.delete(:zipcode)
end
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top