module ActiveRecord::AttributeAssignment
Public Instance Methods
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.
cat = Cat.new(name: "Gorby", status: "yawning") cat.attributes # => { "name" => "Gorby", "status" => "yawning", "created_at" => nil, "updated_at" => nil} cat.assign_attributes(status: "sleeping") cat.attributes # => { "name" => "Gorby", "status" => "sleeping", "created_at" => nil, "updated_at" => nil }
New attributes will be persisted in the database when the object is saved.
Aliased to attributes=
.
# File lib/active_record/attribute_assignment.rb, line 23 def assign_attributes(new_attributes) if !new_attributes.respond_to?(:stringify_keys) raise ArgumentError, "When assigning attributes, you must pass a hash as an argument." end 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
Private Instance Methods
# File lib/active_record/attribute_assignment.rb, line 53 def _assign_attribute(k, v) public_send("#{k}=", v) rescue NoMethodError, NameError if respond_to?("#{k}=") raise else raise UnknownAttributeError.new(self, 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 74 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 64 def assign_nested_parameter_attributes(pairs) pairs.each { |k, v| _assign_attribute(k, v) } end
# File lib/active_record/attribute_assignment.rb, line 80 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 95 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 113 def find_parameter_position(multiparameter_name) multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i end
# File lib/active_record/attribute_assignment.rb, line 109 def type_cast_attribute_value(multiparameter_name, value) multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value end