Using active record's #merge to separate concerns
We’ve all written this kind of code at some point of our lives, a query that
requires a join, and adding a condition to the joined table to limit the
returned results, but then by doing that you’re adding a dependency, and you are
coupling the two models together.
Let’s explain this on an example to make it clear, assume we have a dvd renting
store, and we have a system to manage the users, and dvds rentals, here’s how
the models could look like ( in a very basic form )
This is a basic simple relation, let’s assume the dvds table has a simple flag
that says which dvds were returned and which were not.
To find users that have un returned dvds, we could create a scope like this
This scope has a problem, the thing is that the User
class knows the name of
the field (returned
), and the value it wants it to be (false
), if for any
reason we decided to split the rentals into a separate table, or change the
field’s name or value we need to modify this method too, which resides in the
User
class, it should not have that dependency.
To fix this we could split this condition into a scope in the dvds table
Now the Dvd model only knows what unreturned means, to use that in the users
method we will update the scope to use #merge
It will generate the same SQL query, but without sharing the knowledge of the
field or the value with the User
model