2011-10-18 18 views
5

Los modelos son así:¿Cómo debo escribir el ActiveRecord cuando hay múltiples asociaciones?

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 

Y a continuación son los datos:

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  | 
| |     | 

y ahora quiero encontrar todos los contratos que firmaron con el cliente llamado "Terry", como este:

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 

Alguien me dijo que puede funcionar así:

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

Lo intenté y funciona. Pero aún más cuando el modelo de contrato pertenece a otro modelo, como currency_id, el método anterior no puede funcionar nuevamente.

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

Respuesta

0

¿Ha intentado usar joins: buyer o: user en vez de: customer?

su modelo de contrato no tiene: atributo de cliente/relación

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

mi conjetura es que será equivalente a algo así como

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

comprobar su archivo de registro para ver exactamente lo que se está generando sql en cada caso - log/development.log

+0

lo siento, olvidé agregar la relación de modelo ... Y el archivo de registro es de aproximadamente 40 o 50 líneas porque mi condición real es muy compleja. Estaba totalmente confundido por ellos. – TerryChen

2

Esto se debe a que se supone que no debes usar uniones en conjunción con includes. No se ha enfatizado lo suficiente (y no hay ninguna advertencia en rieles), pero

de selección, se une, grupo, teniendo, etc no funcionan con incluye!

Puede obtener resultados pero solo por casualidad. Y las probabilidades son que se rompa más temprano que tarde.

Parece que hay también una cierta incompatibilidad con ... incluye

Si es necesario utilizar una combinación externa convencional unirse con activerecord> = 3.0 (que es el caso aquí) utiliza el excelente squeel gem. Realmente da el poder de Arel.

probar (con instala squeel):

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

El fuera de la caja se unen hace interno unirse única, que excluye tabla no intersección, haciendo que su meta imposible aquí: comprador & usuario puede ser mutuamente excluyentes. ..

+0

¿NO FUNCIONA? Los usé juntos en otros casos, ¿quieres decir que se puede romper en cualquier momento? – TerryChen

+0

Este es un buen candidato para la raíz del problema, pero su respuesta es un poco vaga al principio (select, etc no funciona con includes, incoherencia). ¿Podría agregar una explicación más clara de estos puntos y/o señalar una explicación autorizada? –

+0

todavía en vacaciones ...intentaré respaldar mi respuesta un poco cuando regrese. – charlysisto

Cuestiones relacionadas