I would like to enhance existing class using instance_eval. There original definition contains validation, which require presence of certain fields, ie:
class Dummy < ActiveRecord::Base
  validates :field, :presence => true 
end
Now I want to change that to optional using instance_eval (or any other method, really):
Dummy.instance_eval do
  ...
end
What would be the proper syntax to remove the validation, so the field is optional. I would rather do this directly on the model layer, instead doing weird hacks in controllers or views. The use of instance_eval is not really required, but as far as I know, this is generally the best way to enhance classes in Rails.
Edit #1
In general - the original class is part of the gem and I don't want to fork it, nor tie to specific release. The general cause is not really important. Simply editing the original model has far worse consequences than monkey patching.
I found a solution, not sure how solid it is, but it works well in my case. @aVenger was actually close with his answer. It's just that the _validators accessor contains only information used for reflection, but not the actual validator callbacks! They are contained in the _validate_callbacks accessor, not to be confused with _validations_callbacks.
Dummy.class_eval do   _validators.reject!{ |key, _| key == :field }    _validate_callbacks.reject! do |callback|     callback.raw_filter.attributes == [:field]   end end   This will remove all validators for :field. If you want to be more precise, you can reject the specific validator for _validators which is the same as the raw_filter accessor of validate callbacks.
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 
                        Easest way to remove all validations:
clear_validators!
                        As I was trying to do this to remove the phone validation from the spree Address model, below is the code I got to work. I added the type check for callback.raw_filter because I only wanted to remove the presence validator on the phone field. I also had to add it because it would fail when trying to run against one of the other validators specified in the Spree::Address model that did not have an 'attributes' key for callback.raw_filter, thus an exception was thrown.
Spree::Address.class_eval do
   # Remove the requirement on :phone being present.
  _validators.reject!{ |key, _| key == :phone }
  _validate_callbacks.each do |callback|
    callback.raw_filter.attributes.delete :phone if callback.raw_filter.is_a?(ActiveModel::Validations::PresenceValidator)
  end
end
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With