为什么使用rails default_scope经常推荐使用?

时间:2014-08-01 19:26:38

标签: ruby-on-rails default-scope

Everywhere on the互联网用户提到使用rails default_scope是一个坏主意,而堆栈溢出中default_scope的热门点击是关于如何覆盖它。这感觉很混乱,值得一个明确的问题(我认为)。

所以:为什么使用导轨default_scope这么糟糕?

5 个答案:

答案 0 :(得分:184)

问题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>

我们在默认范围内遇到了第一个大问题:

<强> =&GT; default_scope will affect your model initialization

在新创建的此类模型的实例中,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的部分)。

现在我们想要获取所有帖子的列表 - 未发布包含 - 比如登录用户的视图。你会发现你必须覆盖&#39;或者&#39;撤消&#39; default_scope的影响。快速谷歌之后,您可能会发现unscoped。看看接下来会发生什么:

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

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

有多种方法可以覆盖default_scope的不同效果。做到这一点很快得到complicated,我认为首先不使用default_scope,这将是一个更安全的选择。

答案 1 :(得分:6)

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

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

答案 2 :(得分:4)

不使用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的帖子。因此,数据库将引发外键冲突,因为该数据库包含引用您要删除的用户的记录。

答案 3 :(得分:0)

我发现default_scope仅在将所有参数排序为ascdesc顺序时才有用。否则我会像瘟疫一样避免它

答案 4 :(得分:0)

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

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

所以这取决于实际需求。