Posted over 7 years ago. Visible to the public. Repeats.

Merge two arbitrary ActiveRecord scopes

Rails 3+ allows you to join two scopes from arbitrary sources by calling the merge method:

Copy
scope1 = User.where(:email => 'foo@bar.com') scope2 = User.where(:first_name => 'hans') merged_scope = scope1.merge(scope2)

merged_scope.all will now trigger a query for the combined scope chain:

Copy
SELECT `users`.* FROM `users` WHERE `users`.`email` = 'foo@bar.com' AND `users`.`first_name` = 'hans'

If you are joining two models, you can also merge scopes for different models.

Also note that #merge has a bug in Rails 3.x where merging two scopes with conditions on the same column will discard all by the last condition. This bug is fixed in our forks.

This is nice for resource_controller and Consul

If you are using resource_controller with Consul, merging allows you to further filter your controller's end_of_association_chain by a Consul power. This is useful when you have a nested controller and want to take advantage of the implicit end_of_association_chain, but still want to authorize access:

Copy
class DocumentsController < ApplicationController resource_controller belongs_to :deal private def end_of_association_chain super.merge(current_power.documents) end end

If you now go to /deals/5/documents you can only access documents which both belong to the deal with the id 5, and are accessible according to your power.

By refactoring problematic code and creating automated tests, makandra can vastly improve the maintainability of your Rails application.

Owner of this card:

Avatar
Henning Koch
Last edit:
9 days ago
by Henning Koch
Keywords:
chain, rails, relation
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Henning Koch to makandra dev
This website uses cookies to improve usability and analyze traffic.
Accept or learn more