互联网上 到处都有人提到使用 rails是个坏主意,而 stackoverflow 上的default_scope
热门default_scope
话题是关于如何覆盖它。这感觉一团糟,值得提出一个明确的问题(我认为)。
那么:为什么不default_scope
推荐使用 rails 呢?
让我们考虑一个基本的例子:
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
将反映出来。因此,虽然您可能希望确保不会偶然列出未发布的帖子,但您现在默认创建已发布的帖子。
考虑一个更详细的例子:
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
,我认为一开始就不要使用,这将是一个更安全的选择。
另一个不使用的原因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
。因此,数据库将引发外键违规,因为它包含引用您要删除的用户的记录。
通常建议不要使用 default_scope,因为它有时被错误地用于限制结果集。default_scope 的一个很好的用途是对结果集进行排序。
我会远离where
在 default_scope 中使用,而是为此创建一个范围。
对我来说不是一个坏主意,但必须谨慎使用!有一种情况,我总是想在设置字段时隐藏某些记录。
default_scope
必须与数据库默认值匹配(例如{ where(hidden_id: nil) }
:)unscoped
一种方法可以避免您的default_scope
所以这将取决于和真正的需求。
我只发现default_scope
仅在将某些参数排序asc
或desc
在所有情况下排序时才有用。否则我会像瘟疫一样避而远之