当存在多个关联时,我应该如何编写ActiveRecord?

时间:2011-10-18 04:12:22

标签: ruby-on-rails-3 activerecord associations

模型是这样的:

class Contract < ActiveRecord::Base  
  belongs_to :buyer, :class_name => 'Customer', :foreign_key => 'buyer_customer_id' 
  belongs_to :user, :class_name => 'Customer', :foreign_key => 'user_customer_id'
  belongs_to :currency
end  

class Customer < ActiveRecord::Base  
  has_many :as_buyer_in_contracts, :class_name => 'Contract', :foreign_key => 'buyer_customer_id'  
  has_many :as_user_in_contracts, :class_name => 'Contract',:foreign_key => 'user_customer_id'  
end

class Currency < ActiveRecord::Base
  has_many :contracts
end

以下是数据:

Contract
+----+-------------------+------------------+-------------+
| id | buyer_customer_id | user_customer_id | currency_id |
+----+-------------------+------------------+-------------+
|  1 |         1         |        3         |      3      |
|  2 |         2         |        2         |      2      |
|  3 |         2         |        1         |      2      |
|    |                   |                  |             |


Customer
+----+-------------------+
| id |       name        |
+----+-------------------+
|  1 |    Terry Brown    |
|  2 |    Tom Green      |
|  3 |    Kate White     |
|    |                   |

Currency
+----+-------------------+
| id |       name        |
+----+-------------------+
|  1 |        EUR        |
|  2 |        USD        |
|  3 |        JPY        |
|    |                   |

现在我想找到所有与客户签名的合同“Terry”,如下:

Contract.where("customers.name like '%Terry%'").includes(:buyer,:user)
#I want 1 and 3, but it can only get 1
Contract.where("customers.name like '%Terry%'").includes(:user, :buyer)
#If I write "user" before "buyer", then I can only get 3

有人告诉我它可以这样工作:

Contract.join(:customer).where("customers.name like '%terry%'").includes(:user,:buyer)
#It works fine.

我尝试了它确实有效。但是当合同模型属于其他模型(例如currency_id)时,上述方法无法再次起作用。

Contract.join(:customer).where("customers.name like '%terry%'").includes(:currency, :user, :buyer)
#>>Mysql2::Error: Unknown column 'customers_contracts.id' in 'field list': ...

2 个答案:

答案 0 :(得分:2)

那是因为你不应该使用与include相结合的连接。它没有得到足够的强调(并且轨道中没有警告)但是

  

选择,加入,分组,拥有等。不要使用包含!

你可能只是偶然得到结果。而且它很可能会比以后更早地破裂。

似乎还有一些不一致的包括......

如果你需要使用传统的外连接和activerecord&gt; = 3.0(这里是这种情况),使用优秀的squeel gem.它确实产生了Arel的力量。

尝试(安装了squeel):

Contract.joins{buyer.outer}.joins{user.outer}.where("name like '%terry%'")

开箱即用的连接仅进行内部连接,不包括非交叉表,这使得您的目标无法实现:买方&amp;用户可以互相排斥...

答案 1 :(得分:0)

您是否尝试过使用加入:买方或:用户而不是:客户?

您的合约模型没有:客户属性/关系

Contract.join(:buyer).where("customers.name like '%terry%'").includes(:currency, :user, :buyer)

我的猜测是等同于

Contract.join("INNER JOIN customers ON customers.id = contracts.buyer_customer_id").where("customers.name like '%terry%'").includes(:currency, :user, :buyer)

检查您的日志文件,以确切了解每种情况下生成的sql - log / development.log