【问题标题】:How can I order nested includes records with Rails 4如何使用 Rails 4 订购嵌套的包含记录
【发布时间】:2014-04-16 23:25:23
【问题描述】:

如标题所述:如何使用 Rails 4 订购嵌套的 includes 记录?

以下是模型的概述:

产品

  • 标题
  • 价格

产品尺寸

  • product_id
  • size_id

尺寸

  • 宽度
  • 身高
  • 订购

一个Product 有许多SizesProductSizeSizes 将通过order 订购Size 型号。我在 Sizes 模型上设置了 default_scopeorder('order DESC')

我希望能够获得products 的列表,然后遍历每个product 并显示可用sizes 的列表,按size order 排序。我想要这一切而又不进行低效查询(n+1 问题),所以我使用includes

为此,我运行Product.includes(:product_sizes => [:size]).all 生成:

SELECT "products".* FROM "products"

SELECT "product_sizes".* FROM "product_sizes" 
WHERE "product_sizes"."product_id" IN (X, X, X, X)

SELECT "sizes".* FROM "sizes" 
WHERE "sizes"."id" IN (X, X, X, X, X, X, X, X) ORDER BY `order` ASC

如您所见,我的订单将关闭,因为它将使用我从 product_sizes 查询中获取记录的顺序。您还可以注意到sizes 的查询确实有ORDER BY 语句,但它不影响最终结果。

我最初的想法是 size 应该只是 joinedproduct_size 查询。不幸的是,我不知道如何使用includes

理想情况下,生成的查询看起来更像:

SELECT "products".* FROM "products"

SELECT "product_sizes".* FROM "product_sizes" 
WHERE "product_sizes"."product_id" IN (X, X, X, X)
JOIN "size" ON product_sizes.size_id = sizes.id
ORDER BY `size`.`order`

SELECT "sizes".* FROM "sizes" 
WHERE "sizes"."id" IN (X, X, X, X, X, X, X, X) ORDER BY `order` ASC

【问题讨论】:

  • 加入sizes会大大增加传输的数据量,因为product_sizes的列对于同一产品的每种尺寸都会重复。 Product.preload(:product_sizes).first.sizes?
  • 不确定它是否有效,但疯狂猜测:Product.preload(:product_sizes).eager_load(:product_sizes => :size),即使有效也不推荐。

标签: mysql ruby-on-rails ruby activerecord ruby-on-rails-4


【解决方案1】:

我继续将sizes 关联直接映射到products。这是我所拥有的:

product.rb 模型:

class Product < ActiveRecord::Base
  has_many :product_sizes
  has_many :sizes, through: :product_sizes, source: :size
end

product_size.rb 型号:

class ProductSize < ActiveRecord::Base
  belongs_to :product
  belongs_to :size
end

size.rb 模型:

class Size < ActiveRecord::Base
  default_scope -> { order(order: :desc)}
end

seeds.rb 文件:(你可以运行 rake db:seed 看看它是如何工作的)

# Size.delete_all
# Product.delete_all
# ProductSize.delete_all

size1 = Size.create!(width: 20, height: 5, order: 3)
size2 = Size.create!(width: 30, height: 15, order: 2)
size3 = Size.create!(width: 10, height: 123, order: 1)
size4 = Size.create!(width: 14, height: 12, order: 4)
size5 = Size.create!(width: 24, height: 32, order: 5)
size6 = Size.create!(width: 45, height: 13, order: 7)
size7 = Size.create!(width: 54, height: 31, order: 6)
size8 = Size.create!(width: 35, height: 14, order: 8)
size9 = Size.create!(width: 42, height: 41, order: 9)
size10 = Size.create!(width: 13, height: 54, order: 10)

product1 = Product.create!(title: "Chair", price: 21.00)
product2 = Product.create!(title: "Table", price: 120.00)
product3 = Product.create!(title: "Microwave", price: 34.00)

ProductSize.create!(size: size1, product: product1)
ProductSize.create!(size: size3, product: product1)
ProductSize.create!(size: size5, product: product1)

ProductSize.create!(size: size1, product: product2)
ProductSize.create!(size: size3, product: product2)
ProductSize.create!(size: size4, product: product2)

ProductSize.create!(size: size1, product: product3)
ProductSize.create!(size: size2, product: product3)
ProductSize.create!(size: size3, product: product3)
ProductSize.create!(size: size8, product: product3)
ProductSize.create!(size: size9, product: product3)
ProductSize.create!(size: size10, product: product3)
ProductSize.create!(size: size4, product: product3)
ProductSize.create!(size: size5, product: product3)
ProductSize.create!(size: size6, product: product3)
ProductSize.create!(size: size7, product: product3)

products = Product.includes(:sizes).references(:sizes).order('"sizes"."order" DESC').to_a
products.each do |product|
  puts product.title
  product.sizes.each { |size| print "#{size.order} " }
  puts    
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-01
    • 2015-02-01
    • 1970-01-01
    • 2022-06-13
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 2013-01-06
    相关资源
    最近更新 更多