Today I want to address what I consider to be one of the most misused features of ActiveRecord.
It is called ActiveRecord Association Extensions.
How to Define An Association Extension
Association Extensions lets you easily add functionality or alter exisiting functionality when dealing with ActiveRecord association. I will refer the following simple code in the post:
What we have here is a
User model which
Account models. Dead simple.
In order to extend the accounts association all we have to do is add a block to it as in:
Which lets us access
@user.accounts.recent as expected.
Use Scopes When It’s Right
The first (and obvious) thought about the latest code snippet is “Why would you wanna do that? Why not just use scope :recent on Account model?!”.
To that I’d answer You’re damn right! This logic should definitely belong to the Account model and be used as a scope so that other references to Account will be able to use it as well.
A Good Case For Association Extensions
This was an easy one and probably not the reason you’re reading this – I want to introduce to you with another case which yells association extenstion a bit louder: Let’s say I want that every account which is added to a user accounts collection will have the kind “UserAccount” as a property.
I will note here that every has_many association includes the << method which may be used as
@user.accounts << Account.new
One way to achieve my goal would be to verify that every time I add an account to a user accounts collection I remember to set its kind property to
"UserAccount". Counting on your memory skills (or even worse – on other programmers memory skills) is a bad habbit, believe me🙂
A better way would be to define a method named
add_account(account) in the User model which will set
account.kind = "UserAccount" before adding it to the accounts collection.
But why should we invent the wheel? ActiveRecord has already taken care of this, presenting you the ultimate solution:
We've practically overriden the
<< method of ActiveRecord association, and by doing this we have the following benefits:
1. We're using ActiveRecord's conventions. Rails is known for its "Convention Over Configuration" attitude and although it may seem negligible this is a huge benefit on its own.
2. We don't have to remember to set anything manually, the setting of the kind proprety will be transparent to us in future uses.
3. Isn't that just beautiful?
One thing to note here that the self reference inside the extension method is NOT the user instance, in order to get that we used
Another great thing about association extensions is they are reusable. In order to make an extension reusable all you have to do is to extract the methods into a module and
:extend that module in the association statement as follows:
Nice, clean and handy.