Read more

Merging two arbitrary ActiveRecord scopes

Henning Koch
June 08, 2011Software engineer at makandra GmbH

(Rails has a method ActiveRecord::Relation#merge that can merge ActiveRecord scopes. However, its behavior has never been clear, and in Rails 7 it still discards conditions on the same column by the last condition. We discourage using #merge!)

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show snapshot

The best way to merge ActiveRecord scopes is using a subquery:

scope_a.where(id: scope_b)

It is a little less concise than #merge, but unambiguous.


Assume a model where a deal has many documents:

class Deal < ApplicationRecord
  has_many :documents

class Document < ApplicationRecord
  belongs_to :deal

You also have a Consul Show snapshot power that specifies which deals and documents are accessible by a user:

class Power
  include Consul::Power
  power :deals do

  power :documents do
    admin? ? Document.all : Document.where(visibility: 'public')

Now there should be a screen to list documents pertaining to a given deal. When we implement the controller, we must filter the document list by two conditions:

  • Only show documents pertaining to the given deal (Deal#documents)
  • Only show documents that the user is allowed to see (Power#documents)

Combine both scopes with scope_a.where(id: scope_b):

class DealDocumentsController < ApplicationController

  def index
    @deal =[:deal_id])
    @documents = current_power.documents.where(id: @deal.documents) # <-- Here


You can also merge scopes for different models: old blog post, card

Posted by Henning Koch to makandra dev (2011-06-08 13:50)