Skip any attribute or block validations at runtime. Tested w/ Rails 5.2.0.
# Skip any attribute or block validations at runtime
# https://github.com/rails/rails/blob/fc5dd0b85189811062c85520fd70de8389b55aeb/activemodel/lib/active_model/validations.rb
# https://github.com/rails/rails/blob/91fd679710118482f718ea710710561f1cfb0b70/activesupport/lib/active_support/callbacks.rb
#
# ex:
# class User < ApplicationRecord
# validates :name, presence: true
# validate :fancy_email_validation
# end
#
# usage:
# user = User.new
# user.save! => false
# user.skip_validations = [:name, :fancy_email_validation]
# user.save! => true
module SkippableValidations
extend ActiveSupport::Concern
included do
attr_accessor :skip_validations
attr_internal :filters
before_validation :skip_callbacks, if: proc{ skip_validations&.any? }
after_validation :reset_callbacks, if: proc{ filters&.any? }
end
private
def skip_callbacks
# determine validators to skip
filters = skip_validations.flat_map do |attribute|
_validators[attribute].presence || attribute
end
# skip any matching validators in the :validate CallbackChain
# ActiveSupport::Callbacks::CallbackChain (nodoc) | https://github.com/rails/rails/blob/91fd679710118482f718ea710710561f1cfb0b70/activesupport/lib/active_support/callbacks.rb#L519
_validate_callbacks.each do |callback|
next unless callback.raw_filter.in?(filters)
singleton_class.skip_callback :validate, :before, callback.raw_filter
end
end
def reset_callbacks
singleton_class.set_callback :validate, :before, *filters
filters.clear
end
end
# Add it to all models
ActiveRecord::Base.include SkippableValidations