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.