class ActiveRecord::Import::Validator
def init_validations(klass)
def init_validations(klass) @validate_callbacks = klass._validate_callbacks.dup @validate_callbacks.each_with_index do |callback, i| filter = callback.respond_to?(:raw_filter) ? callback.raw_filter : callback.filter next unless filter.class.name =~ /Validations::PresenceValidator/ || (!@options[:validate_uniqueness] && filter.is_a?(ActiveRecord::Validations::UniquenessValidator)) callback = callback.dup filter = filter.dup attrs = filter.instance_variable_get(:@attributes).dup if filter.is_a?(ActiveRecord::Validations::UniquenessValidator) attrs = [] else associations = klass.reflect_on_all_associations(:belongs_to) associations.each do |assoc| if (index = attrs.index(assoc.name)) key = assoc.foreign_key.is_a?(Array) ? assoc.foreign_key.map(&:to_sym) : assoc.foreign_key.to_sym attrs[index] = key unless attrs.include?(key) end end end filter.instance_variable_set(:@attributes, attrs.flatten) if @validate_callbacks.respond_to?(:chain, true) @validate_callbacks.send(:chain).tap do |chain| callback.instance_variable_set(:@filter, filter) chain[i] = callback end else callback.raw_filter = filter callback.filter = callback.send(:_compile_filter, filter) @validate_callbacks[i] = callback end end end
def initialize(klass, options = {})
def initialize(klass, options = {}) @options = options @validator_class = klass init_validations(klass) end
def valid_model?(model)
def valid_model?(model) init_validations(model.class) unless model.class == @validator_class validation_context = @options[:validate_with_context] validation_context ||= (model.new_record? ? :create : :update) current_context = model.send(:validation_context) begin model.send(:validation_context=, validation_context) model.errors.clear model.run_callbacks(:validation) do if defined?(ActiveSupport::Callbacks::Filters::Environment) # ActiveRecord >= 4.1 runner = @validate_callbacks.compile env = ActiveSupport::Callbacks::Filters::Environment.new(model, false, nil) if runner.respond_to?(:call) # ActiveRecord < 5.1 runner.call(env) else # ActiveRecord 5.1 # Note that this is a gross simplification of ActiveSupport::Callbacks#run_callbacks. # It's technically possible for there to exist an "around" callback in the # :validate chain, but this would be an aberration, since Rails doesn't define # "around_validate". Still, rather than silently ignoring such callbacks, we # explicitly raise a RuntimeError, since activerecord-import was asked to perform # validations and it's unable to do so. # # The alternative here would be to copy-and-paste the bulk of the # ActiveSupport::Callbacks#run_callbacks method, which is undesirable if there's # no real-world use case for it. raise "The :validate callback chain contains an 'around' callback, which is unsupported" unless runner.final? runner.invoke_before(env) runner.invoke_after(env) end elsif @validate_callbacks.method(:compile).arity == 0 # ActiveRecord = 4.0 model.instance_eval @validate_callbacks.compile else # ActiveRecord 3.x model.instance_eval @validate_callbacks.compile(nil, model) end end model.errors.empty? ensure model.send(:validation_context=, current_context) end end