如何确定是否已加载Rails关联?

时间:2009-09-03 22:03:36

标签: ruby-on-rails activerecord eager-loading

有没有人知道确定Rails关联是否已被急切加载的方法?

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

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

如果项目是急切加载的,那么最有效的加载是:

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

如果项目未加载,则最有效的加载是:

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

但除非我知道它是否是急切的加载,否则我不知道要调用哪些代码来有效地获取记录。如果我在第一种方法没有急切加载时使用它,那么我必须查找超过必要的DB记录。如果我在急切加载时使用第二种方法,那么我的急切加载对象将被忽略。

7 个答案:

答案 0 :(得分:54)

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


对于Rails< 3.1使用loaded_foo?

(自Rails 3.1以来不推荐使用。请参阅:https://github.com/rails/rails/issues/472。)

答案 1 :(得分:48)

item.shipping_infos.loaded?会告诉你。

我必须说,但是这条道路会导致疯狂......在编写测试loaded?的代码以在#detect#find之间做出决定之前,请确保此实例 相对于正在发生的其他事情而言很重要。

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

答案 2 :(得分:21)

我建议使用item.association_cache.keys,它将提供预先加载的关联列表。你是item.association_cache.keys.include吗? :name_of_association

答案 3 :(得分:3)

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

答案 4 :(得分:3)

此问题的解决方案应该是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

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

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

现在:

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

答案 5 :(得分:2)

查看Bullet gem.。这将告诉您何时应该而且不应该使用预先加载。

答案 6 :(得分:1)

association_cached?可能很合适:

item.association_cached?(:shipping_infos)