Ruby-on-rails 如何确定 Rails Association 是否已加载?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1376212/
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 21:42:16  来源:igfitidea点击:

How to Determine if Rails Association is Eager Loaded?

ruby-on-railsactiverecordeager-loading

提问by wbharding

Does anyone know a way to determine if a Rails association has been eager loaded?

有谁知道一种确定 Rails 关联是否已被预先加载的方法?

My situation: I have a result set where sometimes one of the associations is eager loaded, and sometimes it isn't. If it isn't eager-loaded, then I want to look up associations using ActiveRecord's find. If it is eager loaded, I want to use detect.

我的情况:我有一个结果集,有时其中一个关联是急切加载的,有时则不是。如果它不是预先加载的,那么我想使用 ActiveRecord 的 find 查找关联。如果它是预先加载的,我想使用检测。

For example, say that I have a "has_many" array of shipping_info objects in my item model. Then:

例如,假设我的项目模型中有一个“has_many”数组 shipping_info 对象。然后:

If item is eager loaded, most efficient load is:

如果项目是预先加载的,最有效的加载是:

item.shipping_infos.detect { |si| si.region == "United States" }

If item isn't eager loaded, most efficient load is:

如果项目不是预先加载,最有效的加载是:

item.shipping_infos.where(region: "United States").first

But unless I know whether it is eager loaded, I don't know which code to call to get the record efficiently. If I use the first method when it wasn't eager loaded, then I have to look up more DB records than necessary. And if I use the second method when it was eager loaded, then my eager loaded objects are ignored.

但是除非我知道它是否是预先加载的,否则我不知道要调用哪个代码才能有效地获取记录。如果我在没有急切加载时使用第一种方法,那么我必须查找比必要更多的数据库记录。如果我在急切加载时使用第二种方法,那么我急切加载的对象将被忽略。

采纳答案by Bryan Stearns

item.shipping_infos.loaded?will tell you.

item.shipping_infos.loaded?会告诉你。

I gotta say, though: this path leads to madness... before writing code that tests loaded?to decide between #detectand #find, make sure this instance reallymatters, relative to everything else that's going on.

不过,我得说:这条路会导致疯狂……在编写测试loaded?以在#detect和之间#find做出决定的代码之前,确保这个实例真的很重要,相对于正在发生的所有其他事情。

If this isn't the slowest thing your app does, adding extra code paths adds unnecessary complexity. Just because you might waste a little database effort doesn't mean you need to fix it - it probably doesn't matter in any measurable way.

如果这不是您的应用程序所做的最慢的事情,添加额外的代码路径会增加不必要的复杂性。仅仅因为您可能会浪费一点数据库工作并不意味着您需要修复它 - 它可能以任何可衡量的方式无关紧要。

回答by gamov

Use .association(name).loaded?on a record.

使用.association(name).loaded?上的记录。



For Rails < 3.1 use loaded_foo?.

对于 Rails < 3.1 使用loaded_foo?.

(It is deprecated since Rails 3.1. See: https://github.com/rails/rails/issues/472.)

(自 Rails 3.1 起已弃用。请参阅:https: //github.com/rails/rails/issues/472。)

回答by dabobert

I'd suggest using item.association_cache.keys that will provide a list of the eager loaded associations. So you item.association_cache.keys.include?(:name_of_association)

我建议使用 item.association_cache.keys 来提供急切加载关联的列表。那么你item.association_cache.keys.include?(:name_of_association)

回答by phil pirozhkov

association_cached?might be a good fit:

association_cached?可能很合适:

item.association_cached?(:shipping_infos)

回答by Jim Stewart

You can detect whether or not a single association has been loaded with loaded_foo?. For example, if shipping_info was a belongs_to association, then item.loaded_shipping_info? will return true when it's been eager-loaded. Oddly, it appears to return nil (rather than false) when it hasn't been loaded (in Rails 2.3.10 anyway).

您可以使用loaded_ foo来检测单个关联是否已加载。例如,如果shipping_info 是belongs_to 关联,那么item.loaded_shipping_info? 当它被急切加载时将返回 true。奇怪的是,它似乎在尚未加载时返回 nil(而不是 false)(无论如何在 Rails 2.3.10 中)。

回答by Lev Lukomsky

Solution to this problem should be foo.association(:bla).loaded?, BUT it works incorrectly - it checks and marks association as dirty:

这个问题的解决方案应该是foo.association(:bla).loaded?,但它工作不正确 - 它检查并将关联标记为脏:

class Foo; has_one :bla, :autosave => true end
foo.association(:bla).loaded? #=> false
foo.save # saves foo and fires select * from bla

So I've added following extension to ActiveRecord:

所以我在 ActiveRecord 中添加了以下扩展:

module ActiveRecord
  class Base
    def association_loaded?(name)
      association_instance_get(name).present?
    end
  end
end

and now:

现在:

class Foo; has_one :bla, :autosave => true end
foo.association_loaded?(:bla) #=> false
foo.save # saves foo

回答by Bitterzoet

Have a look at the Bullet gem.. This will tell you when you should and should not use eager loading.

看看子弹宝石。. 这会告诉你什么时候应该和不应该使用预先加载。