While working on loose_change tonight, I ran into a situation I hadn’t run into before in Ruby — the need to keep track of attributes on a class that can be inherited. The solution is class_inheritable_accessor. I’d come across blog articles on the subject before, but for the most part, my eyes glazed over. There’s a limit to how much jargon I can process without a concrete example to compare. Here’s a walkthrough of the problem and the solution.
Let’s say you need to keep an attribute on a class (not an instance)
require 'active_support'
require 'active_support/core_ext' # (I'll assume these throughout)
class Payment
class_attribute :acceptable_payors
end
Payment.acceptable_payors = [:tom, :dick]
Great! Now we know who we’ll take money from.
Now, let’s add a credit card payment class:
class Cash < Payment
end
We want to allow the slightly less trustworthy Harry to pay us, as long as it’s cash:
Cash.acceptable_payors << :harry
But now, let’s check our general acceptable payors again:
Payment.acceptable_payors #=> [:tom, :dick, :harry]
Since class_attribute just passes a pointer to the attribute around, subclasses who change something change it for everyone.
So, class_inheritable_accessor to the rescue. Swap it in for class_attribute, and your end result will be:
Cash.acceptable_payors #=> [:tom, :dick, :harry]
Payment.acceptable_payors #=> [:tom, :dick]