Ruby on rails 未能通过与联接表的关联立即加载作用域
我使用联接表account\u category在帐户和类别之间建立了多对多关系。在Ruby on rails 未能通过与联接表的关联立即加载作用域,ruby-on-rails,ruby-on-rails-4,Ruby On Rails,Ruby On Rails 4,我使用联接表account\u category在帐户和类别之间建立了多对多关系。在帐户类中设置默认关系很容易: has_many :account_category has_many :categories, :through => :account_category 我搞不懂的是如何正确地界定额外的自定义类别 has_many :foobar_categories, -> { where type: "foobar" }, through
帐户
类中设置默认关系很容易:
has_many :account_category
has_many :categories, :through => :account_category
我搞不懂的是如何正确地界定额外的自定义类别
has_many :foobar_categories,
-> { where type: "foobar" },
through: :account_category,
source: :category
这会导致加载foobar_类别失败:
# This is a N + 1 query
Account.includes(:foobar_categories).all.each do
# do stuff with account.foobar_categories
end
有人知道我可能做错了什么吗?是否真的不可能通过关联来加载作用域为多的对象
编辑:到目前为止,有两个回答建议在类别上使用范围。我不认为类别的范围是正确的,原因有二:
在“关联的即时加载”部分中,它显示了在范围关联中这应该是可能的
即使要使用范围,您如何加载关联的范围
编辑2:我终于找到了问题的根源。方法调用隐藏在类中,与重写关联的我的关联同名。为我的浏览网站道歉,并感谢那些花时间回答的人。我将这篇文章标记为删除,因为错误在于我们的代码而不是Rails。我建议使用范围而不是自定义关联
范围:foobar_categories->{includes(:categories)。其中(名称:'foobar')}在模型上定义范围:
class Category < ActiveRecord::Base
def self.foobar
where("categories.name = 'foobar'")
end
end
当您有多个要加载的自定义类别时,这就不太管用了。在我的例子中,实际上有4个类似的自定义关联我需要急切地加载并稍后访问。此外,我认为您不能急切地加载关联的范围。您将如何从对Account的调用中加载它。这样,只要您想访问某个帐户的foobar_类别,对集合的迭代就不会导致对DB的额外调用?这忽略了对关联本身的需要。我不想要所有foobar_类别,我想要一个特定帐户的所有foobar_类别,一个特定帐户的所有foobar2_类别,等等。然后将范围移动到该类别,然后调用像account.categories.foobar
(请参见编辑以回答)如何加载范围?这是否仍然会导致每次调用account.categories.foobar时都调用db?此外,我认为最好按照jamesy829在define\u singleton\u方法
的元编程中所建议的那样设置一个范围,这将进行一次查询,以获得每个帐户的类别
。如果您不想这样做,请提前加载<代码>帐户.all.包括(:categories)。每个do Account.categories.foobar end
。你最终会写4次完全相同的范围;这是元编程的主要好处之一。这仍然会导致N+1查询Account.all.includes(:categories)。每个{| Account | Account.categories.foobar_categories}
都会为每个帐户生成一个额外的DB调用,因为DB必须进行一个新调用以确定作用域是什么。Includes仅适用于对categories的初始调用,但作用域中的where子句意味着rails需要额外的DB调用。编辑:为了明确起见:我测试了这一点,以确定情况确实如此。
Account.includes(:categories).merge(Category.foobar).each do |a|
a.categories.each do |c|
puts c.created_at
end
end