Ruby on rails Rails 3.2基于复杂关系组织报告

Ruby on rails Rails 3.2基于复杂关系组织报告,ruby-on-rails,report,rails-activerecord,Ruby On Rails,Report,Rails Activerecord,我正在为一家仓储/运输公司开发一个具有以下数据关系的程序。关于以下关系,最简单的是仓库从不同的承运商(客户)处接收原材料(产品),并将其储存,直到需要将其运至制造厂。当货物离开仓库时,生产设施必须知道每种原材料来自哪个公司。看看下面的ERD。 编辑:我的文本形式的关系 Shipping.rb has_many :product_shipments, :dependent => :destroy has_many :products, :through => :product_shi

我正在为一家仓储/运输公司开发一个具有以下数据关系的程序。关于以下关系,最简单的是仓库从不同的承运商(客户)处接收原材料(产品),并将其储存,直到需要将其运至制造厂。当货物离开仓库时,生产设施必须知道每种原材料来自哪个公司。看看下面的ERD。

编辑:我的文本形式的关系

Shipping.rb

has_many :product_shipments, :dependent => :destroy
has_many :products, :through => :product_shipments
belongs_to :product
belongs_to :shipment
product_Shipping.rb

has_many :product_shipments, :dependent => :destroy
has_many :products, :through => :product_shipments
belongs_to :product
belongs_to :shipment
product.rb

has_many :product_shipments
has_many :shipments, :through => :product_shipments, :dependent => :destroy
belongs_to :client
client.rb

  has_many :products, :dependent => :destroy
我在按照需求的格式生成查询时遇到了问题。发货报告有一个日期,必须遍历每个客户,并列出在给定日期发货到制造工厂的产品。它需要动态生成,并按如下方式格式化

Shipment Date: 2013-01-01

Client: 12 Name: ACME Widget Co

Product Name | Product Code | Qty Shipped
_________________________________________ 
nuts & bolts |      gj-3423 |          25
steel sheet  |      4g-2394 |          10
dc Motor     |      cj-c213 |           4


Client: 14 Name: Blah Blah, Inc

Product Name | Product Code | Qty Shipped
_________________________________________ 
spacers      |      gj-3423 |          15
epoxy        |      4g-2394 |          10
dc Motor     |      24-gj19 |           6

Client: 15 Name: Sample Co, Inc

Product Name | Product Code | Qty Shipped
_________________________________________ 
hot roll 48  |      cg-3423 |          15
welding wir  |      4g-2394 |          10
dc Motor     |      c2-1241 |           6
.
.
.
.
问题是使用ActiveRecord生成查询。在下面的ex中,很容易获取给定日期的装运和产品。要抓住原材料来源的原始客户,然后动态地迭代到该客户的制造工厂,是不容易的

更新:我现在可以像上面那样对客户和发货进行分组。现在我需要排除在指定日期没有发货的客户。下面的内容虽然有些正确,但仍然给出了可怕的O(n)查询。这是我的

@clients = Client.includes(:products => :shipments)
@clients.each do |c|
  puts c.name
  c.products.each do |p|
    p.shipments.where("ship_date like '#{@ship_date.strftime("%Y-%m-%d")}%'").each do |s|
      s.product_shipments.joins(:product).each do |ps|
        puts s.bill_of_lading + " " + ps.product_id.to_s + " " + ps.product.product_name.to_s + " " + ps.product.product_code + " " +ps.qty_shipped.to_s + " " + s.ship_date.to_s
        end
    end
  end
end

我的问题是如何组织查询,从客户开始,然后列出“2012-06-30”发货的产品。从这个角度来看,查询变得古怪。我不确定如何在远离关系的情况下生成带有活动记录的查询。

更新:好的,查看您在报告中期望的结果,需要从ProductShipping中提取值(如quantity属性),因此product\u Shipping必须包含在我们渴望加载的嵌套关联中,否则,ProductShipping不会实例化,它仅用作联接表

因此,您需要的不是
Client.includes(:products=>shippings).

@clients = Client.includes(:products => {:product_shipments => :shipment}).
                  where("shipments.ship='#{ship_date}'")
现在我不完全理解您的域模型,但是当有很多嵌套关联时,我喜欢找出在一对一关系中包含最多信息的关联,因为它们可以被视为中心部分。在这种情况下,产品和装运都可以理解为“主模型”产品装运的扩展

因此,你可以写(尊重德米特定律):

在确保了关联的镜像后,您现在可以通过products获取product_装运,并在DB上无O(n)调用的情况下获取您的报告:

@client.map {|c| c.products.map {|p| p.product_shipments} }.flatten.each do |ps|
  puts ps.details
end
更新结束


必须立即加载关联的模型,否则将进入臭名昭著的O(n)查询


顺便说一句,rails直接从发货连接到产品,假设您有一个
has\u many:through
has\u和\u属于\u many
关联,因此无需使用连接表(aka product\u-shipping)

更新:Ok查看报告中预期的结果,ProductShipping的值(与quantity属性一样)需要拉出,因此product_装运必须包含在我们急于加载的嵌套关联中,否则ProductShippings不会实例化,它仅用作联接表

因此,您需要的不是
Client.includes(:products=>shippings).

@clients = Client.includes(:products => {:product_shipments => :shipment}).
                  where("shipments.ship='#{ship_date}'")
现在我不完全理解您的域模型,但是当有很多嵌套关联时,我喜欢找出在一对一关系中包含最多信息的关联,因为它们可以被视为中心部分。在这种情况下,产品和装运都可以理解为“主模型”产品装运的扩展

因此,你可以写(尊重德米特定律):

在确保了关联的镜像后,您现在可以通过products获取product_装运,并在DB上无O(n)调用的情况下获取您的报告:

@client.map {|c| c.products.map {|p| p.product_shipments} }.flatten.each do |ps|
  puts ps.details
end
更新结束


必须立即加载关联的模型,否则将进入臭名昭著的O(n)查询


顺便说一句,rails会直接从装运到产品,前提是您有一个
has\u many:through
has\u和\u属于\u many
关联,因此无需使用联接表(也称为产品装运)我是这样做的。也许不是最好的方法,但很接近。感谢@charlysisto通过轻松加载关系向我发送了正确的方向。我在查找表的联接查询中仍然得到了O(n),但可能更糟。任何改进请发表评论,以便我可以改进答案

@clients = Client.order("clients.id ASC").includes(:products => :shipments).where("shipments.ship_date like '#{ship_date}'")
@clients.each do |c|
  puts c.name
  c.products.each do |p|
    p.shipments.each do |s|
      s.product_shipments.joins(:product).each do |ps|
        puts shipment and products stuff
      end
    end
end

我是这样做的。也许不是最好的方法,但很接近。感谢@charlysisto通过轻松加载关系向我发送了正确的方向。我在查找表的连接查询中仍然得到了O(n),但可能更糟。任何改进请发表评论,以便我改进答案

@clients = Client.order("clients.id ASC").includes(:products => :shipments).where("shipments.ship_date like '#{ship_date}'")
@clients.each do |c|
  puts c.name
  c.products.each do |p|
    p.shipments.each do |s|
      s.product_shipments.joins(:product).each do |ps|
        puts shipment and products stuff
      end
    end
end

这就是我在该查找表中存储装运数量的方式。我意识到我没有准确回答您的问题。但通过客户端启动查询的目标是否与您显示的结果相同?上述内容与我希望实现的格式不匹配。您提供的代码将输出shipme中每个项目的日期nts。请仔细查看我试图实现的上述输出。整个报告中只会显示一次日期。这就是我在查找表中存储装运数量的方式。我意识到我没有准确地回答您的问题。但是通过客户端启动查询的目标是否与您显示的结果相同?上面没有匹配我想要实现的格式。您提供的代码将输出装运中每个项目的日期。请仔细查看我试图实现的上述输出。日期将仅为disp