在rails中迭代嵌套对象的最佳方法是什么

时间:2013-12-13 16:33:08

标签: ruby-on-rails ruby

您好我想问哪一个更好,如果两个都不是一个好的方法那么迭代嵌套模型的最佳方法是什么。

方法#1。

@categories = Category.all

@categories.each do |category|
   category.sub_categories.each do |sub_category|
     puts sub_category.name
   end
end

假设我有100个类别,每个类别包含100个子类别,因此该appraoch将生成100x100个查询

方法#2。

@categories = Category.all
@sub_categories = SubCategory.all

@categories.each do |category|
    @sub_categories.each do |sub_category|
        if category.id == sub_category.category_id
          puts sub_category.name
        end
    end
end

只有2个查询但会迭代“@sub_categories”100次。

我想知道哪一个更好?

2 个答案:

答案 0 :(得分:5)

第一个肯定更好,特别是因为您可以使用Rails' eager loading来减少查询。

这是我要做的:

#controller  
@categories = Category.includes(:sub_categories)

#view, haml-style  
%ul
  - @categories.each do |category|
    %li
      %h2= category.name
      %ul
        - category.sub_category.each do |sub_category|
          %li= sub_category.name

为什么这样更好?

  1. 使用Rails急切加载减少查询:上面的控制器行最多将运行2次查询
  2. 更简单,更清晰的代码
  3. 您在视图/输出中避免使用复杂且不必要的代码来检查category.id == sub_category.category_id的匹配项。
  4. 关于第二个例子的进一步说明

    假设您有10个类别,每个类别包含10个子类别,总共100个。第一个例子将在@category上进行10次迭代,每次在includes(:sub_categories)上进行10次迭代,对于(这是模糊数学)110“数组迭代”总计。

    第二个例子将在@category上进行10次迭代,每次在@sub_categories上进行100次迭代,对于(模糊数学再次)1010“数组迭代”总计。这肯定更糟。

答案 1 :(得分:1)

方法#2是你更好的选择。这就是为什么......

正如您所指出的,方法#1将查询数据库100次(实际上是101次,包括第一次查询),其中方法#2仅查询两次。 Ruby在处理数组时非常有效,因此迭代数组(特别是只有100条记录)的性能最低。虽然数据库查询,即使rails非常擅长缓存结果,但处理起来仍然非常昂贵。