Class: PassthruValidator

Inherits:
ActiveModel::EachValidator
  • Object
show all
Defined in:
app/validators/passthru_validator.rb

Overview

This validator passes through the file upload validations on a record attribute to an associated record. Useful e.g. with the forms that are not aware of the actual record’s validators but they still need to apply the same validators as in the model they represent. Needs to be configured with the target class and optionally the target attribute where the validators are fetched from. By default the attribute name matches the attribute the validator is set for. Works only for each validators.

Example:

class ParticipantForm < Decidim::Form
  # Passes both the validator class only
  validates :avatar_image, passthru: { to: Person }

  # Passes both the validator class and attribute
  validates :image, passthru: { to: Person, attribute: :avatar_image }
end

Instance Method Summary collapse

Instance Method Details

#target_attribute(default = nil) ⇒ Object



65
66
67
# File 'app/validators/passthru_validator.rb', line 65

def target_attribute(default = nil)
  options[:attribute] || default
end

#target_classObject



61
62
63
# File 'app/validators/passthru_validator.rb', line 61

def target_class
  options[:to]
end

#target_instance(record) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'app/validators/passthru_validator.rb', line 69

def target_instance(record)
  instance_attributes = begin
    if options[:with].respond_to?(:call)
      options[:with].call(record)
    else
      options[:with] || {}
    end
  end
  instance_attributes.each do |key, val|
    instance_attributes[key] = val.call(record) if val.respond_to?(:call)
  end

  target_class.new(instance_attributes)
end

#target_validators(attribute) ⇒ Object



57
58
59
# File 'app/validators/passthru_validator.rb', line 57

def target_validators(attribute)
  target_class.validators_on(target_attribute(attribute))
end

#validate_each(record, attribute, value) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'app/validators/passthru_validator.rb', line 21

def validate_each(record, attribute, value)
  return unless target_class

  dummy_attr = target_attribute(attribute)

  # Create a dummy record for which the validations are actually run on
  dummy = validation_record(record)

  target_validators(attribute).each do |validator|
    next unless validator.is_a?(ActiveModel::EachValidator)
    next unless check_validator_conditions(dummy, validator)

    dummy.errors.clear
    validator.validate_each(dummy, dummy_attr, value)
    dummy.errors[dummy_attr].each do |err|
      record.errors.add(attribute, err)
    end
  end
end

#validation_record(record) ⇒ Object

Creates a dummy validation record that passes the correct file upload validation context from the original record for the validators.



43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'app/validators/passthru_validator.rb', line 43

def validation_record(record)
  dummy = target_instance(record)
  if dummy.is_a?(Decidim::Attachment)
    if record.respond_to?(:attached_to)
      dummy.attached_to = record.attached_to
    elsif record.respond_to?(:organization)
      dummy.attached_to = record.organization
    end
  elsif dummy.respond_to?(:organization=) && record.respond_to?(:organization)
    dummy.organization = record.organization
  end
  dummy
end