2010-02-22 25 views
19

द्वारा जोड़े गए ActiveRecord सत्यापन को हटा या ओवरराइड करना मैं अपने रेल एप्लिकेशन में प्रमाणीकरण के लिए क्लीयरेंस का उपयोग कर रहा हूं। Clearance::User मिक्सिन मेरे User मॉडल में कुछ सत्यापन जोड़ता है, लेकिन इनमें से एक है जिसे मैं निकालना या ओवरराइड करना चाहता हूं। ऐसा करने का सबसे अच्छा तरीका क्या है?सुपरक्लास या मिश्रित

प्रश्न में मान्यता

validates_uniqueness_of :email, :case_sensitive => false 

जो अपने आप में बुरा नहीं है, लेकिन मैं :scope => :account_id जोड़ने के लिए की आवश्यकता होगी। समस्या यह है कि अगर मैं अपने User मॉडल

validates_uniqueness_of :email, :scope => :account_id 

में जोड़ना मैं दोनों सत्यापन प्राप्त है, और एक क्लीयरेंस मेरा से अधिक प्रतिबंधात्मक है कहते हैं, इसलिए मेरा कोई प्रभाव नहीं है। मुझे यह सुनिश्चित करने की ज़रूरत है कि केवल मेरा रन चलता है। मैं यह कैसे करु?

उत्तर

6

मैं समाप्त हो गया "को सुलझाने" निम्नलिखित हैक के साथ समस्या:

  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 

किसी को भी एक बेहतर तरीका के जानता है, मैं बहुत आभारी होंगे:

इस कोड है।

+1

रेल 3 के रूप में, आप errors.delete उपयोग कर सकते हैं: ऊपर के उदाहरण में, इस तरह दिखता है। –

4

मुझे हाल ही में यह समस्या थी और 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 

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 
+1

दुर्भाग्य से मेरे लिए मैं सुपरक्लास नहीं बदल सकता, यह एक मणि में है। – Theo

+0

यह आपके चेक इंजन प्रकाश पर टेप डालने जैसा है और कह रहा है कि यह काम करता है। – courtsimas

-1

यहाँ एक रेल 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 
मेरे लिए काम किया है
1

मैं जानता हूँ कि मैं खेल के लिए देर हो रही है, लेकिन कैसे के बारे में:

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 
प्रारंभ में एक

?

1

त्रुटियां। डिलीट (कुंजी) किसी विशेषता के लिए सभी त्रुटियों को हटा देती है और मैं केवल एक विशेषता से संबंधित विशिष्ट प्रकार की त्रुटि को हटाना चाहता हूं। यह निम्नलिखित विधि किसी भी मॉडल में जोड़ा जा सकता है।

हटाए जाने पर संदेश लौटाता है, अन्यथा।आंतरिक डेटा संरचनाओं को संशोधित किया जाता है ताकि अन्य सभी विधियों को त्रुटि हटाने के बाद अपेक्षित कार्य करना चाहिए।

MIT License

विधि के तहत जारी होने के बाद सत्यापन चलाने की है मॉडल से त्रुटि दूर करने के लिए।

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"}) 
-1

मेरे लिए नीचे दिए गए कोड अपने मॉडल पर पर्याप्त था। मैं ज़िप कोड को मान्य नहीं करना चाहता हूं।

after_validation :remove_nonrequired 

def remove_nonrequired 
    errors.messages.delete(:zipcode) 
end 
+3

आप मजाक कर रहे हैं, है ना? –

+0

मेरे लिए त्रुटि को हटा दिया गया है, लेकिन मॉडल पर "अमान्य" स्थिति नहीं है। – PJSCopeland

4

मैं स्प्री उत्पाद संपत्ति :value मान्यता को दूर करने की जरूरत है और यह वहाँ Klass.class_eval के साथ एक सरल समाधान और AciveRecord::Base

module Spree 
    class ProductProperty < Spree::Base 

    #spree logic 

    validates :property, presence: true 
    validates :value, length: { maximum: 255 } 

    #spree logic 


    end 
end 

की clear_validators! लगता है और यहाँ

Spree::ProductProperty.class_eval do  
    clear_validators! 
    validates :property, presence: true 
end 
+0

क्या यह बेस क्लास पर भी वैधकर्ता को नहीं हटाता है, और इसलिए अन्य सभी सबक्लास? –

+0

https://github.com/rails/rails/blob/e3ceb28e66ca6e869f8f9778dc42672f48001a90/activemodel/lib/active_model/validations.rb#L233 के अनुसार यह सिर्फ स्थानीय स्तर पर सेट सत्यापन/कॉलबैक के instantiated रीसेट करता है। मुझे लगता है कि कॉलबैक का सेट अलग-अलग वर्ग पर सेट नहीं है, सभी श्रृंखला। मुझे व्युत्पन्न कक्षाओं के सत्यापन के साथ समस्याएं नहीं थीं। –

+0

मुझे लगता है कि इसे इस तरह जाना चाहिए: 'वर्ग सबक्लास <अभिभावक; class_eval {clear_validators!}; end'। शायद आपके ऐप में लेक्सिकल गुंजाइश और वास्तविक गुंजाइश का मिलान हुआ, लेकिन 'Parent.class_eval' में वैश्विक रनटाइम गुंजाइश होगी, इसलिए उत्पादन में यदि आप उम्मीद करते हैं कि आपके ऐप में माता-पिता के पास कहीं और मान्यकर्ता हैं तो आपको आश्चर्यचकित किया जाएगा। –

8

मैं था इसे ओवरराइड जीईएम कांटा और एक साधारण जांच जोड़ें, जिसे तब ओवरराइड किया जा सकता है। मेरा उदाहरण एक चिंता का उपयोग करता है।

चिंता:

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 
0

रेल 4 में, आप skip_callback(:validate, :name_of_validation_method) उपयोग करने के लिए सक्षम होना चाहिए ... यदि आप एक सुविधा नाम सत्यापन विधि है। (अस्वीकरण: मैंने इसका परीक्षण नहीं किया है।) यदि नहीं, तो आपको उस कॉल को खोजने के लिए कॉलबैक की सूची में हैक करना होगा, जिसे आप छोड़ना चाहते हैं, और इसकी filter ऑब्जेक्ट का उपयोग करें।

उदाहरण:

मैं एक साइट रेल 4.1.11 और स्प्री 2.4.11.beta के प्रयोग पर काम कर रहा हूँ, 2.1.4 से स्प्री उन्नत बनाया था। हमारा कोड ऐतिहासिक उद्देश्यों के लिए, एक तालिका में Spree::Variant एस की कई प्रतियों को संग्रहीत करता है।

अपग्रेड के बाद, अब मणि 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 की श्रृंखला पूरी तरह से कॉलबैक दूर करने के लिए प्रकट होता है।

एनबी। मुझे instance_variable_get@attributes के लिए उपयोग करना पड़ा है, क्योंकि इसमें इसके लिए कोई एक्सेसर नहीं है।आप ब्लॉक में भी c.filter.options देख सकते हैं; संग्रह से एक त्रुटि को दूर करने के: (क्षेत्र)

c.filter.options 
#=> {:case_sensitive=>true, :allow_blank=>true, :conditions=>#<Proc:... (lambda)>} 
संबंधित मुद्दे