How to remove validation using instance_eval clause in Rails?

后端 未结 18 1832
情话喂你
情话喂你 2021-02-01 02:11

I would like to enhance existing class using instance_eval. There original definition contains validation, which require presence of certain fields, ie:

class Du         


        
相关标签:
18条回答
  • 2021-02-01 02:56

    One solution is to extend validates :

    #no need of instance_eval just open the class
    class Dummy < ActiveRecord::Base
      #validates :field, :presence => true 
    
      def self.validates(*attributes)
        if attributes.first == :field #=> add condition on option if necessary
          return # don't validate
        else
          super(*attributes) #let normal behavior take over
        end
      end
    end
    

    And no that's not monkey-patching but extending or decorating a behavior. Rails 3.1 is built on the idea of "multi- inheritance" with module inclusion, specifically to allow this kind agility.

    update #2

    One caveat is you must load the class with the redefined validates method before the gem containing the call to validates. To do so, require the file in config/application.rb after require "rails/all" as suggested in the railsguides. Something like that :

    require File.expand_path('../boot', __FILE__)
    
    require 'rails/all' # this where rails (including active_record) is loaded
    require File.expand_path('../dummy' __FILE__) #or wherever you want it
    
    #this is where the gems are loaded...
    # the most important is that active_record is loaded before dummy but...
    # not after the gem containing the call to validate :field
    if defined?(Bundler)
      Bundler.require *Rails.groups(:assets => %w(development test))
    end
    

    Hope it works now!

    0 讨论(0)
  • 2021-02-01 02:56

    If you doesn't want to make any changes in Parent class then first clear all validations in child class and copy all required validation from parent class to child class

      class Dummy < ActiveRecord::Base
          validates :property, presence: true
          validates :value, length: { maximum: 255 }
      end
    

    And override it in child class

    Dummy.class_eval do    
      clear_validators!
      validates :property, presence: true
    end
    
    0 讨论(0)
  • 2021-02-01 02:58

    Easest way to remove all validations:

    clear_validators!
    
    0 讨论(0)
  • 2021-02-01 03:01

    I think this is the most actual solution at this moment (I'm using rails 4.1.6):

    # Common ninja
    class Ninja < ActiveRecord::Base
      validates :name, :martial_art, presence: true
    end
    
    # Wow! He has no martial skills
    Ninja.class_eval do
      _validators[:martial_art]
        .find { |v| v.is_a? ActiveRecord::Validations::PresenceValidator }
        .attributes
        .delete(:martial_art)
    end
    
    0 讨论(0)
  • 2021-02-01 03:01

    This does not directly answer the question but here's an option you should consider in such a situation: instead of disabling validation, you could set the required fields in a before_validation hook.

    Since you don't need those required fields, set them with some dummy data that satisfies the validation and forget about them.

    No ugly monkey patching.

    0 讨论(0)
  • 2021-02-01 03:04

    I'd have to look more into the code and help, but I'm thining it might be possible to inspect the list of validators of the class, and then modify the entry for the validation you want to change to add in an :if => :some_function conditional to it.

    You'll need to do it only once for production (so it can be put inside an initializer, but for development you'll need to put it in the model, or somewhere else that will get loaded each time the corresponding model is (perhaps an observer?).

    (I'll edit the answer with more information as I come to research it.)

    0 讨论(0)
提交回复
热议问题