aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/attribute_methods
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/attribute_methods')
-rw-r--r--activerecord/lib/active_record/attribute_methods/before_type_cast.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb7
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb13
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb24
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb9
5 files changed, 25 insertions, 30 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
index 9ee9a7815f..fd61febd57 100644
--- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
+++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
@@ -57,7 +57,7 @@ module ActiveRecord
# task.attributes_before_type_cast
# # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
def attributes_before_type_cast
- @attributes.each_with_object({}) { |(k, v), h| h[k] = v.value_before_type_cast }
+ @attributes.values_before_type_cast
end
private
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index 1c81a5b71b..cadad60ddd 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -83,12 +83,9 @@ module ActiveRecord
end
def get_primary_key(base_name) #:nodoc:
- return 'id' if base_name.blank?
-
- case primary_key_prefix_type
- when :table_name
+ if base_name && primary_key_prefix_type == :table_name
base_name.foreign_key(false)
- when :table_name_with_underscore
+ elsif base_name && primary_key_prefix_type == :table_name_with_underscore
base_name.foreign_key
else
if ActiveRecord::Base != self && table_exists?
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 8c1cc128f7..10869dfc1e 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -81,17 +81,10 @@ module ActiveRecord
# Returns the value of the attribute identified by <tt>attr_name</tt> after
# it has been typecast (for example, "2004-12-12" in a date column is cast
# to a date object, like Date.new(2004, 12, 12)).
- def read_attribute(attr_name)
+ def read_attribute(attr_name, &block)
name = attr_name.to_s
- @attributes.fetch(name) {
- if name == 'id'
- return read_attribute(self.class.primary_key)
- elsif block_given? && self.class.columns_hash.key?(name)
- return yield(name)
- else
- return nil
- end
- }.value
+ name = self.class.primary_key if name == 'id'
+ @attributes.fetch_value(name, &block)
end
private
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index 188d5d2aab..f439bd1ffe 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -33,19 +33,29 @@ module ActiveRecord
class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
self.skip_time_zone_conversion_for_attributes = []
-
- matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
- decorate_matching_attribute_types(matcher, :_time_zone_conversion) do |type|
- TimeZoneConverter.new(type)
- end
end
module ClassMethods
private
- def create_time_zone_conversion_attribute?(name, column)
+
+ def inherited(subclass)
+ # We need to apply this decorator here, rather than on module inclusion. The closure
+ # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
+ # sub class being decorated. As such, changes to `time_zone_aware_attributes`, or
+ # `skip_time_zone_conversion_for_attributes` would not be picked up.
+ subclass.class_eval do
+ matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
+ decorate_matching_attribute_types(matcher, :_time_zone_conversion) do |type|
+ TimeZoneConverter.new(type)
+ end
+ end
+ super
+ end
+
+ def create_time_zone_conversion_attribute?(name, cast_type)
time_zone_aware_attributes &&
!self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) &&
- (:datetime == column.type)
+ (:datetime == cast_type.type)
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 246a2cd8ba..b3c8209a74 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -69,16 +69,11 @@ module ActiveRecord
def write_attribute_with_type_cast(attr_name, value, should_type_cast)
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
- type = type_for_attribute(attr_name)
-
- unless has_attribute?(attr_name) || self.class.columns_hash.key?(attr_name)
- raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
- end
if should_type_cast
- @attributes[attr_name] = Attribute.from_user(value, type)
+ @attributes.write_from_user(attr_name, value)
else
- @attributes[attr_name] = Attribute.from_database(value, type)
+ @attributes.write_from_database(attr_name, value)
end
value