覆盖Rails default_scope

时间:2009-12-02 16:36:53

标签: ruby-on-rails

如果我有一个带默认范围的ActiveRecord :: Base模型:

class Foo < ActiveRecord::Base

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

end

有没有办法在没有的情况下使用Foo.find条件执行default_scope ?换句话说,您可以覆盖默认范围吗?

我原本以为在名称中使用'default'会表示 可以覆盖,否则会被称为global_scope,对吗?

9 个答案:

答案 0 :(得分:209)

在Rails 3中:

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

答案 1 :(得分:148)

简短回答:除非你真的需要,否则不要使用default_scope。使用命名范围可能会更好。话虽如此,如果需要,可以使用with_exclusive_scope覆盖默认范围。

有关详细信息,请查看this question

答案 2 :(得分:102)

如果您只需更改default_scope中定义的顺序,则可以使用reorder method

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

答案 3 :(得分:45)

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这样的内容:{{1}}。

但仍然如果可以,请避免使用{{1}}。这是为了你自己的利益。

答案 4 :(得分:14)

您可以使用with_exclusive_scope方法覆盖默认范围。所以:

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

答案 5 :(得分:5)

Rails 3 default_scope似乎没有像在Rails 2中那样被覆盖。

e.g。

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!

答案 6 :(得分:5)

使用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)

答案 7 :(得分:2)

好吧,您可以随时使用旧时最喜欢的find_by_sql和完整的查询。 例如:     Model.find_by_sql(“SELECT * FROM models WHERE id = 123”)

答案 8 :(得分:0)

在Rails 5.1+(可能是更早的版本,但我已经测试过它可以在5.1上运行)上,可以取消对特定列的作用域,该imho是以一种可以删除default_scope的方式的理想解决方案在命名范围内使用。对于OP default_scope

Foo.unscope(where: :bar)

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

两者都将导致不应用原始范围的sql查询,但是会应用任何其他条件合并到区域中。