Переопределение 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.