Переопределение Rails default_scope

Если у меня есть модель ActiveRecord:: Base с областью по умолчанию:

class Foo < ActiveRecord::Base

  default_scope :conditions => ["bar = ?",bar]

end

Есть ли способ сделать Foo.find без использования условий default_scope? Другими словами, вы можете переопределить область по умолчанию?

Я бы подумал, что использование 'default' в имени предположило бы, что он был переопределяемым, иначе его можно было бы назвать чем-то вроде global_scope, right?

Ответ 1

Короткий ответ: Не используйте default_scope, если вам действительно не нужно. Вероятно, вам будет лучше с помощью названных областей. С учетом сказанного вы можете использовать with_exclusive_scope для переопределения области по умолчанию, если вам нужно.

Посмотрите этот вопрос для более подробной информации.

Ответ 2

В Rails 3:

foos = Foo.unscoped.where(:baz => baz)

Ответ 3

Если вам нужно изменить порядок, определенный в default_scope, вы можете использовать метод reorder.

class Foo < ActiveRecord::Base
  default_scope order('created_at desc')
end

Foo.reorder('created_at asc')

запускается следующий SQL:

SELECT * FROM "foos" ORDER BY created_at asc

Ответ 4

Так как 4.1 вы можете использовать ActiveRecord::QueryMethods#unscope для борьбы с масштабом по умолчанию:

class User < ActiveRecord::Base
  default_scope { where tester: false }
  scope :testers, -> { unscope(:where).where tester: true }
  scope :with_testers, -> { unscope(:where).where tester: [true, false] }
  # ...
end

Теперь возможно unscope, например: :where, :select, :group, :order, :lock, :limit, :offset, :joins, :includes, :from, :readonly, :having.

Однако, пожалуйста, избегайте использования default_scope, если можете. Это для вашего же блага.

Ответ 5

Вы можете переопределить область по умолчанию с помощью метода with_exclusive_scope. Итак:

foos = Foo.with_exclusive_scope { :conditions => ["baz = ?", baz] }

Ответ 6

Rails 3 default_scope не выглядит переопределенным, как в Rails 2.

например.

class Foo < ActiveRecord::Base
  belongs_to :bar
  default_scope :order=>"created_at desc"
end

class Bar < ActiveRecord::Base
  has_many :foos
end

> Bar.foos
  SELECT * from Foo where bar_id = 2 order by "created_at desc";
> Bar.unscoped.foos
  SELECT * from Foo;  (WRONG!  removes the "has" relationship)
> Bar.foos( :order=>"created_at asc" )  # trying to override ordering
  SELECT * from Foo where bar_id = 2 order by "created_at desc, created_at asc"

В моем приложении, используя PostgreSQL, порядок в области WINS по умолчанию. Я удаляю все мои default_scopes и кодируя его явно везде.

Pitfall Rails3!

Ответ 7

С Rails 3+ вы можете использовать комбинацию unscoped и merge:

# model User has a default scope
query = User.where(email: "[email protected]")

# get rid of default scope and then merge the conditions
query = query.unscoped.merge(query)

Ответ 8

Ну, вы всегда можете использовать старую временную любимую find_by_sql с полным запросом. Например:   Model.find_by_sql ( "SELECT * FROM models WHERE id = 123" )

Ответ 9

В Rails 5. 1+ (и, может быть, раньше, но я проверял, что он работает на 5.1) можно отменить выборку конкретного столбца, что является идеальным решением для удаления default_scope способом, который можно использовать внутри именованной области. В случае ОП default_scope,

Foo.unscope(where: :bar)

Или

scope :not_default, -> { unscope(where: :bar) }
Foo.not_default

В результате будет получен SQL-запрос, который не применяет исходную область, но применяет любые другие условия, объединяемые в arel.