Rails合并多个ActiveRecord查询

时间:2013-12-10 05:01:02

标签: ruby-on-rails rails-activerecord

有人可以指出ActiveRecord是如何从Left Outer Join查询中生成嵌套哈希的吗?

我正在为复杂查询做一个急切的加载,其中需要将不同的WHERE子句应用于has_many关联表。当Rails生成查询以获取应用条件的关联时,我没有得到预期的结果。

我能够将结果构建成片段 - 用于驱动表,并单独用于has_many关联。现在我需要将关联表的结果合并到驱动表中。

或者简单来说,我在应用程序中有以下表格。

Items
___________________
| id | item_name  |
___________________
| 1  | "Item One" |
| 1  | "Item One" |
| 1  | "Item One" |
| 1  | "Item One" |
| 1  | "Item One" |
___________________

Inventories
_________________
| id | quantity |
_________________
| 1  | 10       |
| 1  | 10       |
| 1  | 10       |
| 1  | 10       |
| 1  | 10       |
_________________

Transactions
_________________________________________
| id | item_id | tran_status | tran_qty |
_________________________________________
| 1  | 1       | "ordered"   | 1        |
| 2  | 1       | "picked"    | 1        |
| 3  | 1       | "ordered"   | 4        |
| 4  | 1       | "canceled"  | 5        |
| 5  | 1       | "ordered    | 2        |
_________________________________________

Adjustments
_______________________________________
| id | item_id | adj_status | adj_qty |
_______________________________________
| 1  | 1       | "adjusted" | 1       |
| 4  | 1       | "canceled" | 1       |
_______________________________________

我正在尝试使用以下格式为AJAX操作创建JSON响应(使用JBuilder)。

[{"id": 1, 
  "name": "Item One",
  "inventory": {"quantity": 10},
  "transactions": [ {"tran_status": "Ordered", "tran_qty": 1},
                    {"tran_status": "Picked",  "tran_qty": 1},
                    {"tran_status": "Ordered", "tran_qty": 4},
                    {"tran_status": "Ordered", "tran_qty": 2} ],
  "adjustments":  [ {"adj_status": "Adjusted", "adj_qty": 1} ]
 }
]

请注意,“已取消”状态的记录将被排除在外。

既然可能会为多个项目请求这个,我想在查询期间做一个急切的负载。

但是,以下查询不起作用。 Rails生成左外连接查询并破坏该方。

  Item.includes(:inventory).
       includes(:transactions).
       where("transactions.status not in ('canceled')").
       references(:transactions).
       includes(:adjustments).
       where("adjustments.status not in ('canceled')").
       references(:adjustments).
       where(id: params[:item])

所以,我尝试做的是分三步执行查询,最后在JBuilder中迭代创建一个哈希或Openstruct。

  items = Item.includes(:inventory).
  item_ids =  items.collect(&:id)
  trans = Transaction.where(item_id: item_ids).where("status not in ('canceled')")
  adjs = Adjustment.where(item_id: item_ids).where("status not in ('canceled')")

现在我想将所有这些合并为一个哈希数组。

我意识到Rails会在内部做这样的事情,并考虑利用现有的知识,而不是用我有限的知识构建一种效率较低的方法。

任何帮助都将不胜感激。

更新

问题在于尝试自己构建解决方案。核心问题是让Rails生成具有应用于关联表的条件的查询。接受的答案是建立与条件的关联的建议(可以在接受的答案的讨论主题中找到)。

2 个答案:

答案 0 :(得分:1)

如果我找对你,你需要迭代项目:

items = Item.includes(:inventory)
result = []
items.each do |i|
  result << {
     :item => i,
     :trans => Transaction.where(item_id: i.id ).where("status not in ('canceled')"),
     :adjs => Adjustment.where(item_id: i.id).where("status not in ('canceled')")
  }    
end

或者您可以使用单个集合在数组中获取它:

result = Item.includes(:inventory, :transactions, :adjustments).collect { |i| i, 
       i.transactions.where("status not in ('canceled')"), 
       i.adjustments.where("status not in ('canceled')") 
   }

,前提是您已正确设置关联

答案 1 :(得分:0)

require 'json'

hash_arr = []

Item.includes(:inventories,:transactions,:adjustments).all.each do |item|
  hash = {"id"=>item.id,
          "name"=>item.name,
           "inventory"=>item.inventories.count,
  "transactions"=>item.transactions.select("tran_status,tran_qty").collect{ |x|          
       {:tran_status=>x.tran_status,:tran_qty=>x.tran_qty} 
  },
  "adjustments"=>item.adjustments.select("adj_status,adj_qty").collect{|x| {:adj_status=>x.adj_status,:adj_qty=>x.adj_qty}
}
   }
  hash_arr.push hash
end

hash_arr.to_json

希望这符合您的要求

或者您可以使用as_json并指定自己的JSON格式(这会更清晰)。查看here