142

互联网上 到处都有人提到使用 rails是个坏主意,而 stackoverflow 上default_scope热门default_scope话题是关于如何覆盖它。这感觉一团糟,值得提出一个明确的问题(我认为)。

那么:为什么不default_scope推荐使用 rails 呢?

4

5 回答 5

206

问题 1

让我们考虑一个基本的例子:

class Post < ActiveRecord::Base
  default_scope { where(published: true) }
end

设置默认值的动机published: true可能是确保您在想要显示未发布的(私人)帖子时必须明确。到目前为止,一切都很好。

2.1.1 :001 > Post.all
  Post Load (0.2ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."published" = 't'

嗯,这几乎是我们所期望的。现在让我们试试:

2.1.1 :004 > Post.new
 => #<Post id: nil, title: nil, published: true, created_at: nil, updated_at: nil>

这里我们遇到了默认范围的第一个大问题:

=> default_scope 会影​​响你的模型初始化

在此类模型的新创建实例中,default_scope将反映出来。因此,虽然您可能希望确保不会偶然列出未发布的帖子,但您现在默认创建已发布的帖子。

问题 2

考虑一个更详细的例子:

class Post < ActiveRecord::Base
  default_scope { where(published: true) }
  belongs_to :user
end 

class User < ActiveRecord::Base
  has_many :posts
end

让我们获取第一个用户的帖子:

2.1.1 :001 > User.first.posts
  Post Load (0.3ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."published" = 't' AND "posts"."user_id" = ?  [["user_id", 1]]

这看起来像预期的那样(确保一直滚动到右侧以查看有关 user_id 的部分)。

现在我们想要获取所有帖子的列表 - 包括未发布的 - 比如说登录用户的视图。您会意识到您必须“覆盖”或“撤消” default_scope. 快速谷歌搜索后,您可能会发现unscoped. 看看接下来会发生什么:

2.1.1 :002 > User.first.posts.unscoped
  Post Load (0.2ms)  SELECT "posts".* FROM "posts"

=> Unscoped 删除通常可能适用于您的选择的所有范围,包括(但不限于)关联。

有多种方法可以覆盖default_scope. 正确地做到这一点很快就会变得复杂default_scope,我认为一开始就不要使用,这将是一个更安全的选择。

于 2014-08-01T19:26:38.360 回答
14

另一个不使用的原因default_scope是当您删除与模型具有一对多关系的default_scope模型实例时

考虑例如:

    class User < ActiveRecord::Base
      has_many :posts, dependent: :destroy
    end 

    class Post < ActiveRecord::Base
      default_scope { where(published: true) }
      belongs_to :user
    end

调用user.destroy会删除所有的帖子published,但不会删除帖子unpublished。因此,数据库将引发外键违规,因为它包含引用您要删除的用户的记录。

于 2018-07-04T07:39:13.100 回答
7

通常建议不要使用 default_scope,因为它有时被错误地用于限制结果集。default_scope 的一个很好的用途是对结果集进行排序。

我会远离where在 default_scope 中使用,而是为此创建一个范围。

于 2017-02-16T15:38:23.593 回答
1

对我来说不是一个坏主意,但必须谨慎使用!有一种情况,我总是想在设置字段时隐藏某些记录。

  1. 最好default_scope必须与数据库默认值匹配(例如{ where(hidden_id: nil) }:)
  2. 当您完全确定要显示这些记录时,总有unscoped一种方法可以避免您的default_scope

所以这将取决于和真正的需求。

于 2019-03-06T22:57:25.703 回答
1

我只发现default_scope仅在将某些参数排序ascdesc在所有情况下排序时才有用。否则我会像瘟疫一样避而远之

于 2018-04-30T06:47:12.873 回答