mirror of https://github.com/rails/rails
much code can be deleted thanks to @tenderlove's refactoring
This commit is contained in:
parent
9897b9a689
commit
6cff09038d
|
@ -49,14 +49,6 @@ module ActiveRecord
|
|||
@attribute_methods_generated ||= false
|
||||
end
|
||||
|
||||
# We will define the methods as instance methods, but will call them as singleton
|
||||
# methods. This allows us to use method_defined? to check if the method exists,
|
||||
# which is fast and won't give any false positives from the ancestors (because
|
||||
# there are no ancestors).
|
||||
def generated_external_attribute_methods
|
||||
@generated_external_attribute_methods ||= Module.new { extend self }
|
||||
end
|
||||
|
||||
def undefine_attribute_methods
|
||||
super if attribute_methods_generated?
|
||||
@attribute_methods_generated = false
|
||||
|
|
|
@ -43,12 +43,6 @@ module ActiveRecord
|
|||
|
||||
if attr_name == primary_key && attr_name != 'id'
|
||||
generated_attribute_methods.send(:alias_method, :id, primary_key)
|
||||
generated_external_attribute_methods.module_eval <<-CODE, __FILE__, __LINE__
|
||||
def id(v, attributes, attributes_cache, attr_name)
|
||||
attr_name = '#{primary_key}'
|
||||
send(attr_name, attributes[attr_name], attributes, attributes_cache, attr_name)
|
||||
end
|
||||
CODE
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -29,35 +29,8 @@ module ActiveRecord
|
|||
cached_attributes.include?(attr_name)
|
||||
end
|
||||
|
||||
def undefine_attribute_methods
|
||||
generated_external_attribute_methods.module_eval do
|
||||
instance_methods.each { |m| undef_method(m) }
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def type_cast_attribute(attr_name, attributes, cache = {}) #:nodoc:
|
||||
return unless attr_name
|
||||
attr_name = attr_name.to_s
|
||||
|
||||
if generated_external_attribute_methods.method_defined?(attr_name)
|
||||
if attributes.has_key?(attr_name) || attr_name == 'id'
|
||||
generated_external_attribute_methods.send(attr_name, attributes[attr_name], attributes, cache, attr_name)
|
||||
end
|
||||
elsif !attribute_methods_generated?
|
||||
# If we haven't generated the caster methods yet, do that and
|
||||
# then try again
|
||||
define_attribute_methods
|
||||
type_cast_attribute(attr_name, attributes, cache)
|
||||
else
|
||||
# If we get here, the attribute has no associated DB column, so
|
||||
# just return it verbatim.
|
||||
attributes[attr_name]
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# We want to generate the methods via module_eval rather than define_method,
|
||||
# because define_method is slower on dispatch and uses more memory (because it
|
||||
# creates a closure).
|
||||
|
@ -67,19 +40,9 @@ module ActiveRecord
|
|||
# we first define with the __temp__ identifier, and then use alias method to
|
||||
# rename it to what we want.
|
||||
def define_method_attribute(attr_name)
|
||||
cast_code = attribute_cast_code(attr_name)
|
||||
|
||||
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
||||
def __temp__
|
||||
#{internal_attribute_access_code(attr_name, cast_code)}
|
||||
end
|
||||
alias_method '#{attr_name}', :__temp__
|
||||
undef_method :__temp__
|
||||
STR
|
||||
|
||||
generated_external_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
||||
def __temp__(v, attributes, attributes_cache, attr_name)
|
||||
#{external_attribute_access_code(attr_name, cast_code)}
|
||||
read_attribute('#{attr_name}') { |n| missing_attribute(n, caller) }
|
||||
end
|
||||
alias_method '#{attr_name}', :__temp__
|
||||
undef_method :__temp__
|
||||
|
@ -87,6 +50,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
private
|
||||
|
||||
def cacheable_column?(column)
|
||||
if attribute_types_cached_by_default == ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
|
||||
! serialized_attributes.include? column.name
|
||||
|
@ -94,24 +58,6 @@ module ActiveRecord
|
|||
attribute_types_cached_by_default.include?(column.type)
|
||||
end
|
||||
end
|
||||
|
||||
def internal_attribute_access_code(attr_name, cast_code)
|
||||
"read_attribute('#{attr_name}') { |n| missing_attribute(n, caller) }"
|
||||
end
|
||||
|
||||
def external_attribute_access_code(attr_name, cast_code)
|
||||
access_code = "v && #{cast_code}"
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
|
||||
|
@ -120,7 +66,9 @@ module ActiveRecord
|
|||
# If it's cached, just return it
|
||||
@attributes_cache.fetch(attr_name.to_s) { |name|
|
||||
column = @columns_hash.fetch(name) {
|
||||
return self.class.type_cast_attribute(name, @attributes, @attributes_cache)
|
||||
return @attributes.fetch(name) {
|
||||
@attributes[self.class.primary_key] if name == 'id'
|
||||
}
|
||||
}
|
||||
|
||||
value = @attributes.fetch(name) {
|
||||
|
|
Loading…
Reference in New Issue