RoR ActiveRecord查询产生意外结果

时间:2014-01-02 03:34:31

标签: ruby-on-rails active-record-query

我有一个测试应用程序,模型如下

ActiveRecord::Schema.define(version: 20140102023300) do

  create_table "customers", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "order_products", force: true do |t|
    t.integer  "customer_id"
    t.integer  "order_id"
    t.integer  "product_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "orders", force: true do |t|
    t.text     "description"
    t.integer  "customer_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "products", force: true do |t|
    t.string   "description"
    t.float    "item_price"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

end

协会如下

class Customer < ActiveRecord::Base
  has_many :orders
end

class Order < ActiveRecord::Base
  belongs_to :customer
  has_many :order_products
end

class OrderProduct < ActiveRecord::Base
  belongs_to :order
end

然后我用seeds.rb播种了数据库,如下所示:

customers = Customer.create([{:name => 'Alex'}, {:name => 'Clare'}, {:name => 'Bob'}, {:name => 'Ian'}])

orders = Order.create([  
  {:description => 'description for order 1',:customer_id => 1},
  {:description => 'description for order 2',:customer_id => 2},
  {:description => 'description for order 3',:customer_id => 2},
  {:description => 'description for order 4',:customer_id => 1},
  {:description => 'description for order 5',:customer_id => 4}
  ])

orderproducts = OrderProduct.create([
  {:customer_id => 1, :order_id => 1, :product_id => 1},
  {:customer_id => 1, :order_id => 1, :product_id => 2},
  {:customer_id => 1, :order_id => 2, :product_id => 4},
  {:customer_id => 1, :order_id => 2, :product_id => 7},
  {:customer_id => 1, :order_id => 2, :product_id => 3},
  {:customer_id => 2, :order_id => 1, :product_id => 5},
  {:customer_id => 2, :order_id => 1, :product_id => 6},
  {:customer_id => 2, :order_id => 2, :product_id => 3},
  {:customer_id => 2, :order_id => 2, :product_id => 4},
  ])

products = Product.create([
  {:description => 'teddy bear', :item_price => 19.95},
  {:description => 'doll', :item_price => 24.00},
  {:description => 'lego', :item_price => 16.00},
  {:description => 'toy truck', :item_price => 29.95},
  {:description => 'crayons pk10', :item_price => 17.90},
  {:description => 'sketch pad', :item_price => 21.50},
  {:description => 'football', :item_price => 10.55},
  ])

然后在Rails控制台中,我正在加载一个包含客户列表的变量:

@customers = Customer.all

当我运行此命令时:@customers.find(1).orders我正确地获取

Order id: 1, description: "description for order 1", customer_id: 1, created_at: "2014-01-02 02:51:36", updated_at: "2014-01-02 02:51:36">, 

Order id: 4, description: "description for order 4", customer_id: 1, created_at: "2014-01-02 02:51:36", updated_at: "2014-01-02 02:51:36">] 

然后我想查询每个订单中的项目。为简单起见,我们要说我想在1号订单中找到产品,对于客户1

我尝试了这个查询:@customers.find(1).orders.find(1).order_products但是我得到了这个结果:

OrderProduct id: 1, customer_id: 1, order_id: 1, product_id: 1, created_at: "2014-01-02 02:51:36", updated_at: "2014-01-02 02:51:36">,

OrderProduct id: 2, customer_id: 1, order_id: 1, product_id: 2, created_at: "2014-01-02 02:51:36", updated_at: "2014-01-02 02:51:36">, 

OrderProduct id: 6, customer_id: 2, order_id: 1, product_id: 5, created_at: "2014-01-02 02:51:36", updated_at: "2014-01-02 02:51:36">, 

OrderProduct id: 7, customer_id: 2, order_id: 1, product_id: 6, created_at: "2014-01-02 02:51:36", updated_at: "2014-01-02 02:51:36">

看起来它正在返回查询的orders.find(1).order_products部分的结果,因为所有结果都是order_id: 1。问题是此结果集包含customer_id: 12的结果。

我真正想要看到的是order 1customer 1的产品。你能帮我理解我需要的正确查询吗?

3 个答案:

答案 0 :(得分:1)

您的查询基本上会返回属于OrderProduct的所有Order列表 - 您构建查询的方式,它基本上与User {{1}无关}} 属于。例如 - 根据您的架构 - 客户#1的订单#1,但订单#1也属于客户#2。由于查询适用于属于订单的订单产品,因此订单#1将返回客户#1 客户#2的条目。

由于Order具有OrderProductCustomer的外键,因此您可以尝试使用更明确的查询来检索属于特定的订单产品客户订单:

Order

<强>更新

您的OrderProduct.where(:customer_id => 1, :order_id => 1) 中存在一些导致错综复杂关系的问题。您已定义seeds.rb属于Order,但您的数据库种子表明订单属于多个客户。

Customer

一旦您确保每个订单都与单个客户相关联,您就可以发出原始查询以检索属于用户订单的订单产品:

orderproducts = OrderProduct.create([
  {:customer_id => 1, :order_id => 1, :product_id => 1},
  {:customer_id => 1, :order_id => 1, :product_id => 2},
  {:customer_id => 1, :order_id => 2, :product_id => 4},
  {:customer_id => 1, :order_id => 2, :product_id => 7},
  {:customer_id => 1, :order_id => 2, :product_id => 3},
  {:customer_id => 2, :order_id => 1, :product_id => 5}, # Order 1 already belongs to Customer 1
  {:customer_id => 2, :order_id => 1, :product_id => 6}, # Order 1 already belongs to Customer 1
  {:customer_id => 2, :order_id => 2, :product_id => 3}, # Order 2 already belongs to Customer 1
  {:customer_id => 2, :order_id => 2, :product_id => 4}, # Order 2 already belongs to Customer 1
  ])

答案 1 :(得分:0)

如果您了解customer_idorder_id,则可以OrderProduct查询

OrderProduct.where(customer_id: 1, order_id: 1)

但是,您也可以利用活动记录关联来获得类似

的内容
Customer.find(1).orders.first.order_products # to get all order_products of the first order of the customer.

OR

Customer.find(1).where(order_id: 1).order_products

请参阅the docs

中的优秀指南

答案 2 :(得分:0)

看起来order_products是订单和产品的连接表。您可能需要查看此处所述的has_many :through关联:http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association