diff options
Diffstat (limited to 'activerecord/lib/active_record/attribute_assignment.rb')
-rw-r--r-- | activerecord/lib/active_record/attribute_assignment.rb | 49 |
1 files changed, 30 insertions, 19 deletions
diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb index 6c5e2ac05d..bf64830417 100644 --- a/activerecord/lib/active_record/attribute_assignment.rb +++ b/activerecord/lib/active_record/attribute_assignment.rb @@ -1,8 +1,8 @@ +require 'active_model/forbidden_attributes_protection' module ActiveRecord module AttributeAssignment extend ActiveSupport::Concern - include ActiveModel::DeprecatedMassAssignmentSecurity include ActiveModel::ForbiddenAttributesProtection # Allows you to set all the attributes by passing in a hash of attributes with @@ -11,7 +11,19 @@ module ActiveRecord # If the passed hash responds to <tt>permitted?</tt> method and the return value # of this method is +false+ an <tt>ActiveModel::ForbiddenAttributesError</tt> # 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 <tt>attributes=</tt>. 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 @@ -44,7 +56,7 @@ module ActiveRecord if respond_to?("#{k}=") raise else - raise UnknownAttributeError, "unknown attribute: #{k}" + raise UnknownAttributeError.new(self, k) end end @@ -75,13 +87,13 @@ module ActiveRecord end end unless errors.empty? - error_descriptions = errors.map { |ex| ex.message }.join(",") + error_descriptions = errors.map(&:message).join(",") raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes [#{error_descriptions}]" end end def extract_callstack_for_multiparameter_attributes(pairs) - attributes = { } + attributes = {} pairs.each do |(multiparameter_name, value)| attribute_name = multiparameter_name.split("(").first @@ -103,7 +115,7 @@ module ActiveRecord end class MultiparameterAttribute #:nodoc: - attr_reader :object, :name, :values, :column + attr_reader :object, :name, :values, :cast_type def initialize(object, name, values) @object = object @@ -114,39 +126,39 @@ module ActiveRecord def read_value return if values.values.compact.empty? - @column = object.class.reflect_on_aggregation(name.to_sym) || object.column_for_attribute(name) - klass = column.klass + @cast_type = object.type_for_attribute(name) + klass = cast_type.klass if klass == Time read_time elsif klass == Date read_date else - read_other(klass) + read_other end end private def instantiate_time_object(set_values) - if object.class.send(:create_time_zone_conversion_attribute?, name, column) + if object.class.send(:create_time_zone_conversion_attribute?, name, cast_type) Time.zone.local(*set_values) else - Time.time_with_datetime_fallback(object.class.default_timezone, *set_values) + Time.send(object.class.default_timezone, *set_values) end end def read_time - # If column is a :time (and not :date or :timestamp) there is no need to validate if + # If column is a :time (and not :date or :datetime) there is no need to validate if # there are year/month/day fields - if column.type == :time + if cast_type.type == :time # if the column is a time set the values to their defaults as January 1, 1970, but only if they're nil { 1 => 1970, 2 => 1, 3 => 1 }.each do |key,value| values[key] ||= value end else # else column is a timestamp, so if Date bits were not provided, error - validate_missing_parameters!([1,2,3]) + validate_required_parameters!([1,2,3]) # If Date bits were provided but blank, then return nil return if blank_date_parameter? @@ -169,17 +181,16 @@ module ActiveRecord end end - def read_other(klass) + def read_other max_position = extract_max_param positions = (1..max_position) - validate_missing_parameters!(positions) + validate_required_parameters!(positions) - set_values = values.values_at(*positions) - klass.new(*set_values) + values.slice(*positions) end # Checks whether some blank date parameter exists. Note that this is different - # than the validate_missing_parameters! method, since it just checks for blank + # than the validate_required_parameters! method, since it just checks for blank # positions instead of missing ones, and does not raise in case one blank position # exists. The caller is responsible to handle the case of this returning true. def blank_date_parameter? @@ -187,7 +198,7 @@ module ActiveRecord end # If some position is not provided, it errors out a missing parameter exception. - def validate_missing_parameters!(positions) + def validate_required_parameters!(positions) if missing_parameter = positions.detect { |position| !values.key?(position) } raise ArgumentError.new("Missing Parameter - #{name}(#{missing_parameter})") end |