Module: ActiveRecord::Scoping::ClassMethods
- Defined in:
- activerecord/lib/active_record/scoping.rb
Instance Method Summary collapse
-
#with_scope(scope = {}, action = :merge, &block) ⇒ Object
with_scope lets you apply options to inner block incrementally.
Instance Method Details
#with_scope(scope = {}, action = :merge, &block) ⇒ Object
with_scope lets you apply options to inner block incrementally. It takes a hash and the keys must be :find
or :create
. :find
parameter is Relation
while :create
parameters are an attributes hash.
class Article < ActiveRecord::Base
def self.create_with_scope
with_scope(:find => where(:blog_id => 1), :create => { :blog_id => 1 }) do
find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
a = create(1)
a.blog_id # => 1
end
end
end
In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of where
, includes
, and joins
operations in Relation
, which are merged.
joins
operations are uniqued so multiple scopes can join in the same table without table aliasing problems. If you need to join multiple tables, but still want one of the tables to be uniqued, use the array of strings format for your joins.
class Article < ActiveRecord::Base
def self.find_with_scope
with_scope(:find => where(:blog_id => 1).limit(1), :create => { :blog_id => 1 }) do
with_scope(:find => limit(10)) do
all # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
end
with_scope(:find => where(:author_id => 3)) do
all # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
end
end
end
end
You can ignore any previous scopings by using the with_exclusive_scope
method.
class Article < ActiveRecord::Base
def self.find_with_exclusive_scope
with_scope(:find => where(:blog_id => 1).limit(1)) do
with_exclusive_scope(:find => limit(10)) do
all # => SELECT * from articles LIMIT 10
end
end
end
end
Note: the :find
scope also has effect on update and deletion methods, like update_all
and delete_all
.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'activerecord/lib/active_record/scoping.rb', line 60 def with_scope(scope = {}, action = :merge, &block) # If another Active Record class has been passed in, get its current scope scope = scope.current_scope if !scope.is_a?(Relation) && scope.respond_to?(:current_scope) previous_scope = self.current_scope if scope.is_a?(Hash) # Dup first and second level of hash (method and params). scope = scope.dup scope.each do |method, params| scope[method] = params.dup unless params == true end scope.assert_valid_keys([ :find, :create ]) relation = construct_finder_arel(scope[:find] || {}) relation.default_scoped = true unless action == :overwrite if previous_scope && previous_scope.create_with_value && scope[:create] scope_for_create = if action == :merge previous_scope.create_with_value.merge(scope[:create]) else scope[:create] end relation = relation.create_with(scope_for_create) else scope_for_create = scope[:create] scope_for_create ||= previous_scope.create_with_value if previous_scope relation = relation.create_with(scope_for_create) if scope_for_create end scope = relation end scope = previous_scope.merge(scope) if previous_scope && action == :merge self.current_scope = scope begin yield ensure self.current_scope = previous_scope end end |