Everywhere on the互联网用户提到使用rails default_scope
是一个坏主意,而堆栈溢出中default_scope
的热门点击是关于如何覆盖它。这感觉很混乱,值得一个明确的问题(我认为)。
所以:为什么使用导轨default_scope
这么糟糕?
答案 0 :(得分:184)
让我们考虑一下基本的例子:
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
将被反映出来。因此,虽然您可能希望确保不会偶然列出未发布的帖子,但您现在默认创建已发布的帖子。
考虑一个更详细的例子:
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
仅在将所有参数排序为asc
或desc
顺序时才有用。否则我会像瘟疫一样避免它
答案 4 :(得分:0)
对我来说,不是一个坏主意,但请务必谨慎使用!在某些情况下,设置字段时我总是想隐藏某些记录。
noBand
必须与数据库默认值匹配(例如:default_scope
){ where(hidden_id: nil) }
方法来避免使用unscoped
所以这取决于实际需求。