class method self.with_scope

Ruby on Rails 3.1.12

Since v2.2.3 Last seen in v3.1.12

Available in: v2.2.3 v2.3.18 v3.0.20 v3.1.12

Signature

self.with_scope(scope = {}, action = :merge, &block)

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.

Parameters

scope opt = {}
action opt = :merge
block block
Source
# File activerecord/lib/active_record/base.rb, line 1169
        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

Defined in activerecord/lib/active_record/base.rb line 1169 · View on GitHub · Improve this page · Find usages on GitHub

Defined in ActiveRecord::Base

Type at least 2 characters to search.

↑↓ navigate · open · esc close