diff options
Diffstat (limited to 'activerecord/lib/active_record')
4 files changed, 66 insertions, 36 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index c129dc8c52..73e473391a 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -92,6 +92,8 @@ module ActiveRecord end def internal_attribute_access_code(attr_name, cast_code) + cast_code = instance_cast_code(attr_name) + access_code = "v = @attributes.fetch(attr_name) { missing_attribute(attr_name, caller) };" access_code << "v && #{cast_code};" @@ -116,6 +118,10 @@ module ActiveRecord def attribute_cast_code(attr_name) columns_hash[attr_name].type_cast_code('v') end + + def instance_cast_code(attr_name) + "@columns_hash[attr_name].type_cast(v)" + end end # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example, @@ -124,10 +130,11 @@ module ActiveRecord self.class.type_cast_attribute(attr_name, @attributes, @attributes_cache) end + private - def attribute(attribute_name) - read_attribute(attribute_name) - end + def attribute(attribute_name) + read_attribute(attribute_name) + end end end end diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 0c8e4e4b9a..fbace73f7a 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -79,6 +79,14 @@ module ActiveRecord super end end + + def instance_cast_code(attr_name) + if serialized_attributes.include?(attr_name) + "v.unserialized_value" + else + super + end + end end def type_cast_attribute_for_write(column, value) 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 2f86e32f41..30ee0947b3 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -16,46 +16,59 @@ module ActiveRecord module ClassMethods protected - # The enhanced read method automatically converts the UTC time stored in the database to the time - # zone stored in Time.zone. - def attribute_cast_code(attr_name) - column = columns_hash[attr_name] - - if create_time_zone_conversion_attribute?(attr_name, column) - typecast = "v = #{super}" - time_zone_conversion = "v.acts_like?(:time) ? v.in_time_zone : v" - - "((#{typecast}) && (#{time_zone_conversion}))" - else - super - end + # The enhanced read method automatically converts the UTC time stored in the database to the time + # zone stored in Time.zone. + def attribute_cast_code(attr_name) + column = columns_hash[attr_name] + + if create_time_zone_conversion_attribute?(attr_name, column) + typecast = "v = #{super}" + time_zone_conversion = "v.acts_like?(:time) ? v.in_time_zone : v" + + "((#{typecast}) && (#{time_zone_conversion}))" + else + super end + end - # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. - # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. - def define_method_attribute=(attr_name) - if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name]) - method_body, line = <<-EOV, __LINE__ + 1 - def #{attr_name}=(original_time) - time = original_time - unless time.acts_like?(:time) - time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time - end - time = time.in_time_zone rescue nil if time - write_attribute(:#{attr_name}, original_time) - @attributes_cache["#{attr_name}"] = time + # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. + # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. + def define_method_attribute=(attr_name) + if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name]) + method_body, line = <<-EOV, __LINE__ + 1 + def #{attr_name}=(original_time) + time = original_time + unless time.acts_like?(:time) + time = time.is_a?(String) ? Time.zone.parse(time) : time.to_time rescue time end - EOV - generated_attribute_methods.module_eval(method_body, __FILE__, line) - else - super - end + time = time.in_time_zone rescue nil if time + write_attribute(:#{attr_name}, original_time) + @attributes_cache["#{attr_name}"] = time + end + EOV + generated_attribute_methods.module_eval(method_body, __FILE__, line) + else + super end + end private - def create_time_zone_conversion_attribute?(name, column) - time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) && column.type.in?([:datetime, :timestamp]) + def instance_cast_code(attr_name) + column = columns_hash[attr_name] + + if create_time_zone_conversion_attribute?(attr_name, column) + typecast = "v = #{super}" + time_zone_conversion = "v.acts_like?(:time) ? v.in_time_zone : v" + + "((#{typecast}) && (#{time_zone_conversion}))" + else + super end + end + + def create_time_zone_conversion_attribute?(name, column) + time_zone_aware_attributes && !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) && column.type.in?([:datetime, :timestamp]) + end end end end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index a2ce620354..93b8e269fb 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -341,6 +341,8 @@ module ActiveRecord @attributes[pk] = nil unless @attributes.key?(pk) + @columns_hash = self.class.columns_hash.dup + @relation = nil @aggregation_cache = {} @association_cache = {} |