Inheritable Attributes in Rails
During a debugging session the other day, I found myself digging into how Rails implements inheritable
attributes. These are an extension to the Class class and deeply intertwined in the inner workings of
Rails. They’re part of ActiveSupport. I haven’t seen much on the net discussing them, and I don’t know
whether that’s because few people have to deal with them directly, they’re mundane, or my search skills
are failing. In any case, I decided to jot down my discoveries.
Inheritable attributes are kind of like class variables, except they’re copy-on-subclass. The subclass
gets a copy of these from the superclass, but the subclass can further modify them independently. One
major use of them in Rails is for STI (Single Table Inheritance) subclasses to inherit the superclass’
associations. The actual association declarations in the superclass (such as has_many, belongs_to, etc.)
create an object stored in an inheritable attribute called reflections. Then once a subclass is created
it gets a copy of this array of reflections and can further refine or extend them. Cool stuff.
But there’s a dark side. I mentioned above that this was found in a debugging session, not just a random
exploration through the Rails source. The way these work depends on the Class#inherited method, which
is called on a superclass whenever a subclass is defined and the subclass is passed as a parameter.
This is where the actual copy-on-subclass logic occurs. If another monkey-patcher messes with the
inherited method, weird things can happen, like a STI subclass losing access to the superclass’
associations.
However, once they’re understood, it’s not so mysterious. Not only that, but they’re a useful item
to keep in your bag of tricks. There are analogs to attr_accessor and similar methods called
class_inheritable_accessor as well as special methods for array and hash versions for those occasions
when you want a subclass to have copy-on-subclass class variables.
potential differences
[/ruby-rails]
permalink
|