Hey guys,
I've posted a fairly large refactoring of rails' attribute related-methods to trac at
http://dev.rubyonrails.org/ticket/9241
As it makes a few non-minor changes to the core of activerecord, I thought I'd post it for review here. I'm especially interested in any breakage that you notice related to either the NoMethodError or @attributes_cache changes.
The patch itself isn't done yet, so don't worry about any 'peculiarities' of the implementation, what I'm concerned about is whether the subtly different semantics and caching introduce any bugs in your applications.
== description follows ==
This patch refactors the attribute-generation methods in ActiveRecord::Base in the following ways:
* Move generation from instance methods to class methods * In addition to accessors, generate mutators * Always generate accessors and mutators, the overhead in development mode is minimal.
It includes one functional change, results of typecasted attributes are cached in a new hash @attributes_cache. The rationale for this change is that repeated access to columns requiring typecasting (such as Times) can be a significant overhead. Code like the following will repeatedly call the Time.parse functions.
50.times { object.created_at }
This can contribute to performance degradation in datetime-heavy applications.
Finally the behaviour of the respond_to? and method_missing methods has changed when you use find with :select.
# OLD @customer = Customer.find(1, :select=>"first_name"). @customer.respond_to?("last_name") # => false @customer.has_attribute?("last_name") # => false @customer.last_name # raises NoMethodError
# NEW @customer = Customer.find(1, :select=>"first_name"). @customer.respond_to?("last_name") # => true @customer.has_attribute?("last_name") # => false @customer.last_name # raises MissingAttributeError
This change simplifies the code somewhat, and also makes it easier to track down bugs in this area. A simple hook is provided so plugin authors can experiment with lazily fetching the missing columns. While this could be useful for large TEXT or BLOB attributes, I don't intend to include functionality like that without battle-testing it in some way.