Ruby-on-rails 为什么通常不推荐使用 rails default_scope?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25087336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:50:25  来源:igfitidea点击:

Why is using the rails default_scope often recommend against?

ruby-on-railsdefault-scope

提问by wrtsprt

Everywhereontheinternet people mention that using the rails default_scopeis a bad idea, and the top hits for default_scopeon stackoverflow are about how to overwrite it. This feels messed up, and merits an explicit question (I think).

无处不互联网人提到,使用轨道default_scope是一个坏主意,而对于排名靠前default_scope的计算器是关于如何将其覆盖。这感觉一团糟,值得一个明确的问题(我认为)。

So: why is using the rails default_scoperecommended against?

那么:为什么要使用default_scope推荐的导轨?

回答by wrtsprt

Problem 1

问题一

Lets consider the basic example:

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

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

The motivation to make the default published: true, might be to make sure you have to be explict when wanting to show unpublished (private) posts. So far so good.

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

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

Well this is pretty much what we expect. Now lets try:

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

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

And there we have the first big problem with default scope:

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

=> default_scope will affect your model initialization

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

In a newly created instance of such a model, the default_scopewill be reflected. So while you might have wanted to be sure to not list unpublished posts by chance, you're now creating published ones by default.

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

Problem 2

问题二

Consider a more elaborate example:

考虑一个更详细的例子:

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

class User < ActiveRecord::Base
  has_many :posts
end

Lets get the first users posts:

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

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]]

This looks like expected (make sure to scroll all the way to the right to see the part about the user_id).

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

Now we want to get the list of all posts - unpublished included - say for the logged in user's view. You'll realise you have to 'overwrite' or 'undo' the effect of default_scope. After a quick google, you'll likely find out about unscoped. See what happens next:

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

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

=> Unscoped removes ALL scopes that might normally apply to your select, including (but not limited to) associations.

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

There are multiple ways to overwrite the different effects of the default_scope. Getting that right gets complicatedvery quickly and I would argue not using the default_scopein the first place, would be a safer choice.

有多种方法可以覆盖default_scope. 获得正确的方法很快就会变得复杂,我认为首先不使用default_scope将是一个更安全的选择。

回答by Koekenbakker28

Another reason to not use default_scopeis when you're deleting an instance of a model that has a 1 to many relation with the default_scopemodel

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

Consider for example:

考虑例如:

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

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

Calling user.destroywill delete all the posts that are published, but it won't delete posts that are unpublished. Hence the database will throw a foreign key violation because it contains records that reference the user you want to remove.

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

回答by nahankid

default_scope is often recommended against because it is sometimes incorrectly used to limit the result set. A good use of default_scope is to order the result set.

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

I would stay away from using wherein default_scope and rather create a scope for that.

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

回答by Moses Liao GZ

I only find default_scopeto be useful only in ordering some parameters to be in ascor descorder in all situation. Otherwise I avoid it like plague

我只发现default_scope仅在对某些参数进行排序ascdesc在所有情况下排序时才有用。否则我会像躲避瘟疫一样避开它

回答by Sposmen

For me is nota bad ideabut must be used with caution!. There is a case where I always wanted to hide certain records when a field is set.

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

  1. Preferably the default_scopemust match with the DB default value (e.g: { where(hidden_id: nil) })
  2. When you are totally sure you want to show those records, there is always the unscopedmethod that will avoid your default_scope
  1. 优选地,default_scope必须与DB默认值相匹配(例如:{ where(hidden_id: nil) }
  2. 当您完全确定要显示这些记录时,总有unscoped一种方法可以避免您的default_scope

So it will depend and the real needs.

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