aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/attribute_methods
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2011-12-01 17:55:27 +0000
committerJon Leighton <j@jonathanleighton.com>2011-12-01 23:41:51 +0000
commitf1a534af98950efd9969deea1540717c4516d673 (patch)
treeee42e61af1e39c9f9f9fab02cce06c83753965ff /activerecord/lib/active_record/attribute_methods
parent47b97a739d5588cfa439a4805fb1ddd3b7a7acbe (diff)
downloadrails-f1a534af98950efd9969deea1540717c4516d673.tar.gz
rails-f1a534af98950efd9969deea1540717c4516d673.tar.bz2
rails-f1a534af98950efd9969deea1540717c4516d673.zip
Remove the need for type_cast_attribute.
This is good because it reduces duplication.
Diffstat (limited to 'activerecord/lib/active_record/attribute_methods')
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb62
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb8
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb19
3 files changed, 47 insertions, 42 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 8eec06302a..41cd194c92 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -33,7 +33,7 @@ module ActiveRecord
if base_class == self
generated_attribute_methods.module_eval do
public_methods(false).each do |m|
- singleton_class.send(:undef_method, m) if m.to_s =~ /^cast_/
+ singleton_class.send(:undef_method, m) if m.to_s =~ /^attribute_/
end
end
end
@@ -49,27 +49,27 @@ module ActiveRecord
# The second, slower, branch is necessary to support instances where the database
# returns columns with extra stuff in (like 'my_column(omg)').
def define_method_attribute(attr_name)
- access_code = attribute_access_code(attr_name)
- cast_code = "v && (#{attribute_cast_code(attr_name)})"
+ internal = internal_attribute_access_code(attr_name)
+ external = external_attribute_access_code(attr_name)
if attr_name =~ ActiveModel::AttributeMethods::NAME_COMPILABLE_REGEXP
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__
def #{attr_name}
- #{access_code}
+ #{internal}
end
- def self.cast_#{attr_name}(v)
- #{cast_code}
+ def self.attribute_#{attr_name}(v, attributes_cache, attr_name)
+ #{external}
end
STR
else
generated_attribute_methods.module_eval do
define_method(attr_name) do
- eval(access_code)
+ eval(internal)
end
- singleton_class.send(:define_method, "cast_#{attr_name}") do |v|
- eval(cast_code)
+ singleton_class.send(:define_method, "attribute_#{attr_name}") do |v, attributes_cache, attr_name|
+ eval(external)
end
end
end
@@ -80,7 +80,7 @@ module ActiveRecord
attribute_types_cached_by_default.include?(column.type)
end
- def attribute_access_code(attr_name)
+ def internal_attribute_access_code(attr_name)
access_code = "(v=@attributes['#{attr_name}']) && #{attribute_cast_code(attr_name)}"
unless attr_name == self.primary_key
@@ -94,6 +94,16 @@ module ActiveRecord
access_code
end
+ def external_attribute_access_code(attr_name)
+ access_code = "v && #{attribute_cast_code(attr_name)}"
+
+ if cache_attribute?(attr_name)
+ access_code = "attributes_cache[attr_name] ||= (#{access_code})"
+ end
+
+ access_code
+ end
+
def attribute_cast_code(attr_name)
columns_hash[attr_name].type_cast_code('v')
end
@@ -103,36 +113,26 @@ module ActiveRecord
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name)
attr_name = attr_name.to_s
- caster = "cast_#{attr_name}"
+ accessor = "attribute_#{attr_name}"
methods = self.class.generated_attribute_methods
- if methods.respond_to?(caster)
+ if methods.respond_to?(accessor)
if @attributes.has_key?(attr_name)
- @attributes_cache[attr_name] || methods.send(caster, @attributes[attr_name])
+ methods.send(accessor, @attributes[attr_name], @attributes_cache, attr_name)
end
+ elsif !self.class.attribute_methods_generated?
+ # If we haven't generated the caster methods yet, do that and
+ # then try again
+ self.class.define_attribute_methods
+ read_attribute(attr_name)
else
- _read_attribute attr_name
- end
- end
-
- def _read_attribute(attr_name)
- attr_name = attr_name.to_s
- attr_name = self.class.primary_key if attr_name == 'id'
-
- unless @attributes[attr_name].nil?
- type_cast_attribute(column_for_attribute(attr_name), @attributes[attr_name])
+ # If we get here, the attribute has no associated DB column, so
+ # just return it verbatim.
+ @attributes[attr_name]
end
end
private
- def type_cast_attribute(column, value)
- if column
- column.type_cast(value)
- else
- value
- end
- end
-
def attribute(attribute_name)
read_attribute(attribute_name)
end
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index e1eb2d6acf..0a4432506f 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -77,14 +77,6 @@ module ActiveRecord
end
end
- def type_cast_attribute(column, value)
- if column && self.class.serialized_attributes[column.name]
- value.unserialized_value
- else
- super
- end
- end
-
def type_cast_attribute_for_write(column, value)
if column && coder = self.class.serialized_attributes[column.name]
Attribute.new(coder, value, :unserialized)
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 7cde9dbffd..d7972917fe 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -19,12 +19,15 @@ module ActiveRecord
# Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
# This enhanced read method automatically converts the UTC time stored in the database to the time
# zone stored in Time.zone.
- def attribute_access_code(attr_name)
- if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
+ def internal_attribute_access_code(attr_name)
+ column = columns_hash[attr_name]
+
+ if create_time_zone_conversion_attribute?(attr_name, column)
<<-CODE
cached = @attributes_cache['#{attr_name}']
return cached if cached
- time = _read_attribute('#{attr_name}')
+ v = @attributes['#{attr_name}']
+ time = #{column.type_cast_code('v')}
@attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time
CODE
else
@@ -32,6 +35,16 @@ module ActiveRecord
end
end
+ def external_attribute_access_code(attr_name)
+ column = columns_hash[attr_name]
+
+ if create_time_zone_conversion_attribute?(attr_name, column)
+ "attributes_cache[attr_name] ||= (#{attribute_cast_code(attr_name)})"
+ else
+ super
+ end
+ end
+
def attribute_cast_code(attr_name)
if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
"v.acts_like?(:time) ? v.in_time_zone : v"