Merging two arbitrary ActiveRecord scopes
Rails 3+ allows you to join two scopes from arbitrary sources by calling the
scope1 = User.where(:email => 'firstname.lastname@example.org') scope2 = User.where(:first_name => 'hans') merged_scope = scope1.merge(scope2)
merged_scope.to_a will now trigger a query for the combined scope chain:
SELECT `users`.* FROM `users` WHERE `users`.`email` = 'email@example.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:
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.