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

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

class Foo < ActiveRecord::Base

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

end

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

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

8 ответов

Решение

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

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

В Rails 3:

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

Если все, что вам нужно, это изменить порядок, определенный в 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.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если сможешь Это для вашего же блага.

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

foos = Foo.with_exclusive_scope { :conditions => ["baz = ?", baz] }
  • with_exclusive_scope документация

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

Foo.unscope(where: :bar)

Или

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

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

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

# model User has a default scope
query = User.where(email: "foo@example.com")

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

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 и кодирую это явно везде.

Касаемо Rails3!

Ну, вы всегда можете использовать старые любимые find_by_sql с полным запросом. Например: Model.find_by_sql("ВЫБРАТЬ * ИЗ МОДЕЛЕЙ, ГДЕ id=123")

Другие вопросы по тегам