覆盖Rails default_scope

Gar*_*eth 150 ruby-on-rails

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

class Foo < ActiveRecord::Base

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

end
Run Code Online (Sandbox Code Playgroud)

有没有办法Foo.find 使用这些default_scope条件?换句话说,您可以覆盖默认范围吗?

我原以为在名称中使用'default'会表明它是可以覆盖的,否则会被称为类似的global_scope,对吧?

Vin*_*ent 210

在Rails 3中:

foos = Foo.unscoped.where(:baz => baz)
Run Code Online (Sandbox Code Playgroud)

  • 这有副作用,如果Post has_many Comment,Post.first.comments.unscoped返回所有注释. (56认同)
  • 一个好的经验法则是只有`unscoped`才能直接跟随模型,例如``Foo.unscoped.blah()`是好的但是从来没有`Foo.blah().unscoped`. (13认同)
  • 警告!Unscoped不会仅删除default_scope,它已在另一条评论中说过,但它确实可以搞砸了. (7认同)
  • 这真让我搞砸了一会儿.特别是如果你最终将它放在一个类方法中:`def self.random; unscoped.order( '兰特()'); end` unscoped删除之前的所有sql,而不仅仅是default_scope下列出的内容.虽然技术上是正确的答案,但要小心使用`unstopped` (3认同)

Pär*_*der 149

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

有关更多详细信息,请查看此问题.

  • >除非确实需要,否则不要使用default_scope.一个很好的建议!谢谢! (9认同)
  • [`with_exclusive_scope`已在rails 3中删除](https://github.com/rails/rails/commit/bd1666ad1de88598ed6f04ceffb8488a77be4385) (5认同)
  • 先生您有点夸大其词了。`default_scope` 是一个很好的工具,在某些情况下你可以用另一种方式,但 `default_scope` 是正确的做法。例如,当你有一个带有 `inactive` 标志的 `Product` 模型时,设置一个 `default_scope { where inactive: false }` 是最好的做法,因为 99% 或情况下你不会想要显示一个不活动的产品。然后你只需在剩下的 1% 的情况下调用 `unscoped`,这可能是一个管理面板。 (5认同)
  • 如此真实.使用`default_scope`可能看起来是个好主意,但在应用程序的生命周期内可能会引起多处麻烦. (2认同)

Gui*_*iGS 106

如果您只需要更改定义的顺序default_scope,则可以使用该reorder方法.

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

Foo.reorder('created_at asc')
Run Code Online (Sandbox Code Playgroud)

运行以下SQL:

SELECT * FROM "foos" ORDER BY created_at asc
Run Code Online (Sandbox Code Playgroud)

  • 提示:定义一个范围,如`scope:without_default_order, - > {reorder("")}`你可以做一些事情,比如`Foo.without_default_order.order("created_at ASC")`在某些情况下,它读得更好(也许不是这个)确切的情况,但我有一个). (3认同)

jib*_*iel 49

既然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
Run Code Online (Sandbox Code Playgroud)

这是目前可能unscope的东西一样::where, :select, :group, :order, :lock, :limit, :offset, :joins, :includes, :from, :readonly, :having.

如果可以,请尽量避免使用default_scope.这是为了你自己的利益.


Joh*_*ley 14

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

foos = Foo.with_exclusive_scope { :conditions => ["baz = ?", baz] }
Run Code Online (Sandbox Code Playgroud)

  • 事实并非如此,它刚被移动:http://apidock.com/rails/ActiveRecord/Scoping/ClassMethods/with_exclusive_scope (3认同)

wbh*_*ing 8

在 Rails 5.1+(也许更早,但我已经测试过它适用于 5.1)上,可以取消特定列的范围,恕我直言,这是以default_scope可在命名范围内使用的方式删除 a 的理想解决方案。在 OP 的情况下default_scope

Foo.unscope(where: :bar)
Run Code Online (Sandbox Code Playgroud)

或者

scope :not_default, -> { unscope(where: :bar) }
Foo.not_default
Run Code Online (Sandbox Code Playgroud)

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


van*_*oom 5

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"
Run Code Online (Sandbox Code Playgroud)

在我的应用程序中,使用PostgreSQL,默认范围WINS中的排序.我正在删除所有的default_scopes并在任何地方显式编码.

陷阱Rails3!


san*_*rvo 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)
Run Code Online (Sandbox Code Playgroud)