Chr*_*rga 5 activerecord group-by ruby-on-rails eager-loading ancestry
我有一个属于类别的条目模型。类别模型使用祖先,以便我可以嵌套类别。
我想按其根类别对所选条目进行分组。我遇到的问题是,为了做到这一点,rails 对每个条目执行查询以获取根类别。因此,如果我有 20 条记录,它将执行 20 个查询以按根类别分组。
我已经通过预先加载类别(如下所示)减少了查询数量,但我不知道如何预先加载类别的根。
这是我正在使用的代码:
控制器
@entries = current_user.entries.includes(:category)
@entries_by_category = @entries.group_by { |entry| entry.category.root }
Run Code Online (Sandbox Code Playgroud)
入口.rb
class Entry < ActiveRecord::Base
belongs_to :category
end
Run Code Online (Sandbox Code Playgroud)
类别.rb
class Category < ActiveRecord::Base
has_ancestry
has_many :entries
end
Run Code Online (Sandbox Code Playgroud)
我试图把默认范围的分类模型,像这样:default_scope { includes(:ancestry) }。但这并没有改变执行查询的数量。而且我无法弄清楚如何includes()在原始查询上使用以包含类别和类别的根。
作为一些额外的信息,类别只能嵌套 2 层深(仅类别和子类别)。所以 root 在技术上意味着父级,它不必遍历多个级别。
有任何想法吗?
我有一个非常类似的问题,只是我想急切地加载类别的path而不只是加载root. 不幸的是,急切加载仅适用于关联。Ancestry 导航器(parent、root、path、ancestors等)都是方法,而不是关联,因此您不能急切地加载它们。
我的解决方案是立即加载条目的类别关联,然后使用模型级缓存(请参阅Railscast #115)来Category缓存path(您可以根据root您的情况进行修改):
类别.rb
def cached_path
Rails.cache.fetch([self, "path"]) { path.to_a }
end
Run Code Online (Sandbox Code Playgroud)
条目控制器.rb
def index
@entries = Entry.includes(:category)
end
Run Code Online (Sandbox Code Playgroud)
视图/条目/index.html.haml
- @entries.each do |entry|
= entry.category.cached_path.map{ |c| c.name }.join(" / ")
Run Code Online (Sandbox Code Playgroud)
希望有帮助。