Allows you to set all the attributes by passing in a hash of attributes with keys matching the attribute names (which again matches the column names).
If the passed hash responds to permitted?
method and the
return value of this method is false
an
ActiveModel::ForbiddenAttributesError
exception is raised.
# File lib/active_record/attribute_assignment.rb, line 14 def assign_attributes(new_attributes) return if new_attributes.blank? attributes = new_attributes.stringify_keys multi_parameter_attributes = [] nested_parameter_attributes = [] attributes = sanitize_for_mass_assignment(attributes) attributes.each do |k, v| if k.include?("(") multi_parameter_attributes << [ k, v ] elsif v.is_a?(Hash) nested_parameter_attributes << [ k, v ] else _assign_attribute(k, v) end end assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty? assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty? end
# File lib/active_record/attribute_assignment.rb, line 41 def _assign_attribute(k, v) public_send("#{k}=", v) rescue NoMethodError if respond_to?("#{k}=") raise else raise UnknownAttributeError, "unknown attribute: #{k}" end end
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 Fixnum and f for Float. If all the values for a given attribute
are empty, the attribute will be set to nil
.
# File lib/active_record/attribute_assignment.rb, line 62 def assign_multiparameter_attributes(pairs) execute_callstack_for_multiparameter_attributes( extract_callstack_for_multiparameter_attributes(pairs) ) end
Assign any deferred nested attributes after the base attributes have been set.
# File lib/active_record/attribute_assignment.rb, line 52 def assign_nested_parameter_attributes(pairs) pairs.each { |k, v| _assign_attribute(k, v) } end
# File lib/active_record/attribute_assignment.rb, line 68 def execute_callstack_for_multiparameter_attributes(callstack) errors = [] callstack.each do |name, values_with_empty_parameters| begin send("#{name}=", MultiparameterAttribute.new(self, name, values_with_empty_parameters).read_value) rescue => ex errors << 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 { |ex| ex.message }.join(",") raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]" end end
# File lib/active_record/attribute_assignment.rb, line 83 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
# File lib/active_record/attribute_assignment.rb, line 101 def find_parameter_position(multiparameter_name) multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i end
# File lib/active_record/attribute_assignment.rb, line 97 def type_cast_attribute_value(multiparameter_name, value) multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value end