覆盖 Rails 的 default_scope

18 浏览
0 Comments

覆盖 Rails 的 default_scope

如果我有一个带有默认作用域的ActiveRecord::Base模型:

class Foo < ActiveRecord::Base
  default_scope :conditions => ["bar = ?",bar]
end

有没有办法在不使用默认作用域条件的情况下执行Foo.find?换句话说,你可以覆盖默认作用域吗?

我本以为在名称中使用“default”会暗示它是可覆盖的,否则它会被称为global_scope之类的,对吗?

0
0 Comments

问题出现的原因:在Rails中,默认情况下,如果没有指定排序方式,查询操作会按照模型的default_scope中定义的顺序进行排序。然而,在某些情况下,我们可能需要改变默认的排序方式。

解决方法:使用reorder方法可以改变default_scope中定义的排序方式。例如,在Foo模型中,如果默认排序方式为created_at desc,我们可以使用Foo.reorder('created_at asc')来改变排序方式为created_at asc

整理成一篇文章:

在Rails中,默认情况下,如果没有指定排序方式,查询操作会按照模型的default_scope中定义的顺序进行排序。然而,在某些情况下,我们可能需要改变默认的排序方式。

如果只是想改变default_scope中定义的排序方式,可以使用reorder方法。例如,在Foo模型中,如果默认排序方式为created_at desc,我们可以使用Foo.reorder('created_at asc')来改变排序方式为created_at asc

reorder方法的使用非常简单,只需在模型的类定义中调用reorder方法,并传入新的排序方式作为参数,即可改变默认的排序方式。

除此之外,我们还可以定义一个新的作用域,来实现不使用默认排序的查询操作。例如,我们可以定义一个名为without_default_order的作用域,使用reorder("")来取消默认排序。然后,我们可以使用Foo.without_default_order.order("created_at ASC")来进行排序,这样的代码可读性更好。

如果需要改变Rails中默认的排序方式,可以使用reorder方法来实现。此外,还可以通过定义新的作用域来实现不使用默认排序的查询操作。

0
0 Comments

在Rails 3中,使用unscoped方法可以绕过默认作用域进行查询。然而,这会导致一个副作用,即如果Post模型具有多个Comment模型,那么Post.first.comments.unscoped将返回所有评论,而不仅仅是没有默认作用域的评论。

这个副作用曾经给我带来了很大的困扰。特别是当你把unscoped放在类方法中时,比如:def self.random; unscoped.order('rand()'); endunscoped将删除所有的SQL查询,而不仅仅是删除默认作用域下的查询。虽然从技术上讲这是正确的,但是在使用unscoped时要小心。

需要注意的是,unscoped并不仅仅删除默认作用域,正如另一个评论中已经提到的,它可能会对其他方面造成混乱。

一个很好的经验法则是,只有在直接跟随在模型之后使用unscoped时才可以使用,例如:Foo.unscoped.blah()是可以的,但是绝对不要使用Foo.blah().unscoped

stackoverflow.com/questions/1834159/…提供了绕过上述副作用的解决方法。

0
0 Comments

在Rails中,使用default_scope可能会导致一些问题,因此不建议使用它,除非你真的有必要。相反,你可以使用命名作用域(named scopes)来取代default_scope。如果你需要覆盖默认作用域,你可以使用with_exclusive_scope

为什么不建议使用default_scope呢?因为它可能会在应用程序的生命周期中引起多个问题。有人在Stack Overflow上提问了类似的问题,并得到了类似的回答:

“在没有必要的情况下,不要使用default_scope。这是一个很好的建议!谢谢!”

实际上,有一些情况下确实需要使用default_scope。比如,在一个Product模型中,有一个inactive标志,如果你希望在大多数情况下不显示不活跃的产品,那么设置一个default_scope { where inactive: false }是一个好主意。对于剩下的1%的情况,你可以调用unscoped来取消作用域,比如在管理员面板中。

然而,default_scope违反了最小惊讶原则(principle of least astonishment),可能会让人感到困惑。因此,一些开发者对之前使用default_scope的决策感到后悔。

总之,除非有必要,否则不要使用default_scope。有些情况下,使用命名作用域或其他方法可能更好。在Rails 3中,with_exclusive_scope已经被移除了,所以如果你在使用Rails 3或更高版本,你需要考虑其他解决方案。

需要注意的是,有一些gem(例如paranoid gem)仍然使用default_scope,但这并不意味着它是一个好的实践。在使用这些gem时,还是要慎重考虑是否真的需要使用default_scope

虽然default_scope在某些情况下是有用的,但在大多数情况下,尽量避免使用它,以免引起不必要的问题。

0