Module: OnForm::MultiparameterAttributes

Included in:
Form
Defined in:
lib/on_form/rails_compat.rb

Instance Method Summary collapse

Instance Method Details

#assign_multiparameter_attributes(pairs) ⇒ Object

Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done by calling new on the column type or aggregation type (through composed_of) object with these parameters. So having the pairs written_on(1) = “2004”, written_on(2) = “6”, written_on(3) = “24”, will instantiate written_on (a date type) with Date.new(“2004”, “6”, “24”). You can also specify a typecast character in the parentheses to have the parameters typecasted before they’re used in the constructor. Use i for Integer and f for Float. If all the values for a given attribute are empty, the attribute will be set to nil.



13
14
15
16
17
# File 'lib/on_form/rails_compat.rb', line 13

def assign_multiparameter_attributes(pairs)
  execute_callstack_for_multiparameter_attributes(
    extract_callstack_for_multiparameter_attributes(pairs)
  )
end

#execute_callstack_for_multiparameter_attributes(callstack) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/on_form/rails_compat.rb', line 19

def execute_callstack_for_multiparameter_attributes(callstack)
  errors = []
  callstack.each do |name, values_with_empty_parameters|
    begin
      if defined?(ActiveRecord::AttributeAssignment::MultiparameterAttribute)
        # ActiveRecord 4.2 and below: you must use MultiparameterAttribute to construct the attribute value.
        # we therefore have to look up which model the attribute actually lives on.
        backing_model, backing_name = backing_for_attribute(name)
        send("#{name}=", ActiveRecord::AttributeAssignment::MultiparameterAttribute.new(backing_model, backing_name.to_s, values_with_empty_parameters).read_value)
      else
        # ActiveRecord 5.0+: you can assign the indexed hash to the column and it will construct the value for you.
        if values_with_empty_parameters.each_value.all?(&:nil?)
          values = nil
        else
          values = values_with_empty_parameters
        end
        send("#{name}=", values)
      end
    rescue => ex
      errors << ActiveRecord::AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
    end
  end
  unless errors.empty?
    error_descriptions = errors.map(&:message).join(",")
    raise ActiveRecord::MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]"
  end
end

#extract_callstack_for_multiparameter_attributes(pairs) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/on_form/rails_compat.rb', line 47

def extract_callstack_for_multiparameter_attributes(pairs)
  attributes = {}

  pairs.each do |(multiparameter_name, value)|
    attribute_name = multiparameter_name.split("(").first
    attributes[attribute_name] ||= {}

    parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value)
    attributes[attribute_name][find_parameter_position(multiparameter_name)] ||= parameter_value
  end

  attributes
end

#find_parameter_position(multiparameter_name) ⇒ Object



65
66
67
# File 'lib/on_form/rails_compat.rb', line 65

def find_parameter_position(multiparameter_name)
  multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i
end

#type_cast_attribute_value(multiparameter_name, value) ⇒ Object



61
62
63
# File 'lib/on_form/rails_compat.rb', line 61

def type_cast_attribute_value(multiparameter_name, value)
  multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
end