Friday, May 28, 2010

Tweaking on Rails 3.0: #3 class_attribute

We all know that class variables in Ruby don't work well with inheritance. For this reason, ActiveSupport originally added class_inheritable_accessor (view source). The method works by using the Class.inherited callback, and copying attributes down to subclasses. This was basically a hack. It failed to work correctly if the parent's accessor was written to after the inherited classes were defined, and it's wasteful to copy attributes to every inheriting class.

Along comes class_attribute (view source). It works by defining the class accessor methods on the class's singleton class. The technique is described in more detail by a article. The win is that we're getting true inheritance and expected behavior.

How do you improve your code in Rails 3? Simply replace the text class_inheritable_accessor with class_attribute!

Tweaking on Rails 3.0: #2 ActiveSupport::Concern

Unless you've been writing your Ruby code in a cave, deep within uninhabited mountains, you have probably seen and written a Ruby module. And it probably went something like this:

Including this into a User model gives us User.awesome, User.make_everyone_awesome, and User#awesome?.

Before getting into ActiveSupport::Concern, you shouldn't be defining the InstanceMethods module and explicitly including it. Remove it now, based on reasons explained by Yehuda Katz. I only provide it in this example for criticism.

In Rails 3, extend your module with ActiveSupport::Concern. This gives you two things:
  • The including class is automatically extended with the ClassMethods module. No more klass.extend(ClassMethods).
  • You get a new method called "included", which provides a terser way to define the idiomatic "self.include(base)" method.
. This is best described by a refactoring of the above example:

As an aside, the Awesomeness module should definitely go into Rails core, but they keep ignoring my requests.

Thursday, May 27, 2010

Tweaking on Rails 3.0: #1 Callback Blocks

There are plenty of articles about the big changes in Rails 3, so I feel motivated to comment on the small ones.
You might be familiar with using a block with a callback. Let's define an article model for our awesome new blogging software. It defines a default title for a newly created article:

Notice that we must pass the new article to the block. In Rails 3, the block is evaluated within the scope of the new instance, so we can change it to look like this:

Extremely minor, but I find myself using block callbacks more often because of it.