mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Remove the need for type_cast_attribute.
This is good because it reduces duplication.
This commit is contained in:
@@ -29,6 +29,10 @@ module ActiveRecord
|
||||
end
|
||||
end
|
||||
|
||||
def generated_attribute_methods
|
||||
@generated_attribute_methods ||= (base_class == self ? super : base_class.generated_attribute_methods)
|
||||
end
|
||||
|
||||
def undefine_attribute_methods
|
||||
if base_class == self
|
||||
super
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1821,7 +1821,7 @@ MSG
|
||||
# Returns true if the specified +attribute+ has been set by the user or by a database load and is neither
|
||||
# nil nor empty? (the latter only applies to objects that respond to empty?, most notably Strings).
|
||||
def attribute_present?(attribute)
|
||||
value = _read_attribute(attribute)
|
||||
value = read_attribute(attribute)
|
||||
!value.nil? || (value.respond_to?(:empty?) && !value.empty?)
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user