Active Record scopes are a great way to introduce domain terms into your code without repeating queries all over the place.

What happens when you want to reuse a scope from one model in another?

Let's go through an example.

Say we have two models: Customer and Device . And a customer has_one :device .

Within Device , I've written a scope to select devices that have been shipped. It looks like this:

class Device < ActiveRecord :: Base scope :shipped , -> { where . not ( shipped_at: nil ) } end

Later on, you want to add a scope to Customer to select all of the customers with a shipped device.

Here's how I would normally write that:

class Customer < ActiveRecord :: Base scope :with_shipped_device , -> { joins ( :device ). where . not ( device: { shipped_at: nil }) end end

And here's the SQL this produces:

SELECT `customers`.* FROM `customers` INNER JOIN `devices` ON `devices`.`customer_id` = `customers`.`id` WHERE (`devices`.`shipped_at` IS NOT NULL)

A few things bug me about this code:

The implementation of both scopes is almost identical I'm not getting to re-use my scope on the Device model Instead of using my domain terms, I'm pretty much writing SQL

Enter Relation#merge

It turns out, there is a way to reduce this type of duplication. You can call merge on any Active Record relation to merge in other scopes - and it works across models.

So, the scope on Customer can be rewritten like so:

class Customer < ActiveRecord :: Base scope :with_shipped_device , -> { joins ( :device ). merge ( Device . shipped ) } end

This produces the exact same SQL query shown above.

I like this code better because...

it's shorter

the query for selecting shipped devices is in one place

it's easier to reason about; a customer with a shipped device is a just that - a customer with a shipped device

Check out merge to see if it helps you improve your scopes.