2010-01-11 10 views
8

Tengo dos modeloscarriles - build_association no está funcionando para una relación has_one y belongs_to

class Subscription < ActiveRecord::Base 
    belongs_to :client 
end 

class Client < ActiveRecord::Base 
    has_one :subscription 
end 

pero cuando intento para crear uno de los padres del niño, por ejemplo, sub.build_client la clave externa no se establece, p.

>> sub = Subscription.new 
=> #<Subscription id: nil, token: nil, user_id: nil, created_at: nil, updated_at: nil, cancelled: nil, active: nil, client_id: nil> 
>> sub.save(false); 
?> client = sub.build_client 
=> #<Client id: nil, server_id: nil, ip: nil, created_at: nil, updated_at: nil> 
>> client.save(false) 
=> true 
>> sub.client_id 
=> nil 
>> sub 
=> #<Subscription id: 4, token: nil, user_id: nil, created_at: "2010-01-11 06:07:45", updated_at: "2010-01-11 06:07:45", cancelled: nil, active: nil, client_id: nil> 

No funciona si hago client.build_subscription

?> client = Client.new 
=> #<Client id: nil, server_id: nil, ip: nil, created_at: nil, updated_at: nil> 
>> client.save(false) 
=> true 
>> sub = client.build_subscription 
=> #<Subscription id: nil, token: nil, user_id: nil, created_at: nil, updated_at: nil, cancelled: nil, active: nil, client_id: 4> 
>> sub.save(false) 
=> true 
>> sub 
=> #<Subscription id: 5, token: nil, user_id: nil, created_at: "2010-01-11 06:09:32", updated_at: "2010-01-11 06:09:32", cancelled: nil, active: nil, client_id: 4> 
>> client 
=> #<Client id: 4, server_id: nil, ip: nil, created_at: "2010-01-11 06:09:02", updated_at: "2010-01-11 06:09:02"> 
>> ^C 

He pasado 3 horas jugando y se puso a ninguna parte. ¿Alguien puede explicar lo que estoy haciendo mal, cosas para comprobar, etc.

Respuesta

9

De acuerdo con las asociaciones de su modelo, un Subscription es hijo de Client.

Si primero crea una suscripción y luego crea un cliente según su primer ejemplo, Rails no tiene manera de establecer un valor de clave externa client_id dentro de la tabla subscriptions porque en ese momento no ha creado el registro del cliente, por lo no hay nada que asociar con la suscripción. Es por eso que primero debe crear el registro principal (es decir, un cliente) y luego asociarlo con un registro de suscripción secundario utilizando el método build_subscription.

+0

gracias John, pensé que este era el caso (sí consulté la guía de rieles pero no pude encontrar esto explicado, así que quería confirmar aquí en stackoverflow). Pero ¿cómo puede ser que con un has_many pertenezca a la relación esto se pueda hacer? – robodisco

+0

Yo también pensé que si no se puede hacer, ¿por qué está el método de compilación allí? Si el foreign_id no se puede establecer, ¿cuál es el uso de ese método en esta relación? – robodisco

+1

Esa es una buena pregunta. –

1

En mis proyectos me tienen muchas asociaciones similares, pero a menudo prohíben el establecimiento de client_id a nula, por lo que no puede crear el objeto hijo sin objeto padre.

Probar:

sub = Subscription.new 
sub.build_client 
sub.save 

Se va a crear y guardar ambos objetos.

0

En uno de los comentarios, pregunta por qué el método build_client está allí. Al guardar el cliente y luego comprueba la client_id en el sub, es nula, sino también si se hubiera llamado

sub.save(validate: false) 

y después se comprueba la client_id en el sub, sería existe. Por lo tanto, aunque requirió un ahorro adicional, todavía tiene la magia de configurar la clave externa para el sub.

1

Parece que se ha corregido en Rails 4.2.5 o anterior. (No estoy seguro de cuál es la versión más antigua con el parche. Solo he probado 4.2.5.)

Cuando se guarda el padre, después de que se inserta el registro padre, se ejecuta automáticamente una actualización para agregar el ID de padre en el registro de niño.

Sin embargo, no he encontrado ninguna documentación sobre este comportamiento, el código relevante o las pruebas automatizadas, por lo que no estoy seguro de si se solucionó intencionadamente y se debe confiar en este comportamiento. Puede ser mejor seguir con las soluciones en las otras respuestas aquí.

Esto también parece ser todavía roto para has_many en Rails 4.2.5.

Cuestiones relacionadas