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 004fc1c commit 86acbf1cc050c8fa8c74a10c735e467fb6fd7df8 @jeremy jeremy committed with tenderlove Aug 30, 2010
2 activerecord/lib/active_record/attribute_methods.rb
@@ -48,7 +48,7 @@ def method_missing(method_id, *args, &block)
def respond_to?(*args)
- self.class.define_attribute_methods
+ self.class.define_attribute_methods unless self.class.attribute_methods_generated?
8 activerecord/lib/active_record/attribute_methods/read.rb
@@ -77,6 +77,12 @@ def define_read_method(symbol, attr_name, column)
# 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, 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'
value = @attributes[attr_name]
@@ -90,8 +96,6 @@ def read_attribute(attr_name)
- else
- nil
5 activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -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
+ alias #{attr_name} _#{attr_name}
generated_attribute_methods.module_eval(method_body, __FILE__, line)

6 comments on commit 86acbf1


This created a lot of confusion today, as we used underscore-prefixed methods in our model code ourselves. Also, i think changes like this should not be part of a minor version bump or a security release.


This commit causes our Rails app to run very slowly and to use about twice the amount of RAM. We tested the following code snippet with Rails at this and the previous commit. With this commit it ran around 15 times slower than with the previous commit.

c = User.first
1000000.times do

We're running Ruby 1.8, so we thought we'd try the same benchmark with Ruby 1.9. With 1.9 there were no problems at all.

In order to fix the performance regression right here and now, we have downgraded to Rails 3.0.5.

My best guess as to why this is happening is that Object#send is much more expensive on 1.8 than 1.9.

Ruby on Rails member

I believe this was reverted though before 3.0.6. @tenderlove, c/d?


You mean it isn't a part of the final 3.0.6 release?

As far as I can see, it is:
It is even mentioned in the release notes:

Ruby on Rails member

Thanks @rasmusrn, you are right. So we were planning to revert it but we didn't. Maybe @jeremy or @tenderlove have something to add, let's wait.

Ruby on Rails member

This commit fixes a bug. The problem is outlined in the comments on 0823bbd

We need to find a way other than reverting this commit to fix the slowness. ❤️

Please sign in to comment.