Permalink
Browse files

Cheaper attribute reads and respond_to?. Add underscore-prefixed meth…

…od aliased to the attribute name so it can be overridden but still called internally.
  • Loading branch information...
1 parent d79b1aa commit e0e3adff0333cb23a63d61a2005cfc44f7f40b52 @jeremy jeremy committed Aug 31, 2010
@@ -48,13 +48,13 @@ def method_missing(method_id, *args, &block)
end
def respond_to?(*args)
- self.class.define_attribute_methods
+ self.class.define_attribute_methods unless self.class.attribute_methods_generated?
super
end
protected
def attribute_method?(attr_name)
- attr_name == 'id' || attributes.include?(attr_name)
+ attr_name == 'id' || @attributes.include?(attr_name)
@josevalim

josevalim Sep 10, 2010

Member

Ctive model API requires attributes method to be implemented. This commit changes it so it requires @attributes instead. I believe it was non intentional?:)

@jeremy

jeremy Sep 10, 2010

Owner

Hmm yeah. This is intentional: building a full attributes hash to check for existence of an attribute is very expensive.

end
end
end
@@ -70,13 +70,19 @@ def define_read_method(symbol, attr_name, column)
if cache_attribute?(attr_name)
access_code = "@attributes_cache['#{attr_name}'] ||= (#{access_code})"
end
- generated_attribute_methods.module_eval("def #{symbol}; #{access_code}; end", __FILE__, __LINE__)
+ generated_attribute_methods.module_eval("def _#{symbol}; #{access_code}; end; alias #{symbol} _#{symbol}", __FILE__, __LINE__)
end
end
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name)
+ send "_#{attr_name}"
+ rescue NoMethodError
+ _read_attribute attr_name
+ end
+
+ def _read_attribute(attr_name)
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id'
if !(value = @attributes[attr_name]).nil?
@@ -89,8 +95,6 @@ def read_attribute(attr_name)
else
value
end
- else
- nil
end
end
@@ -19,12 +19,13 @@ module ClassMethods
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}(reload = false)
+ def _#{attr_name}(reload = false)
cached = @attributes_cache['#{attr_name}']
return cached if cached && !reload
- time = read_attribute('#{attr_name}')
+ time = _read_attribute('#{attr_name}')
@attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time
end
+ alias #{attr_name} _#{attr_name}
EOV
generated_attribute_methods.module_eval(method_body, __FILE__, line)
else

3 comments on commit e0e3adf

Member

josevalim commented on e0e3adf Sep 10, 2010

So maybe we could do AR attributes method faster? Or have a new method called attributed_hash? My point is that ActiveModel ahould rely on a method (like attributes_hash) instead of an instance variable as API.

Owner

jeremy replied Sep 10, 2010

This is internal to Active Record. Active Model definitely shouldn't rely on an instance variable as API.

Member

josevalim replied Sep 11, 2010

Damn, my bad! Just after your last comment I noticed the chAnge was in AR! :D

Please sign in to comment.