2010-01-11 7 views
8

J'ai deux modèlesRails - build_association ne fonctionne pas pour une has_one et les relations belongs_to

class Subscription < ActiveRecord::Base 
    belongs_to :client 
end 

class Client < ActiveRecord::Base 
    has_one :subscription 
end 

mais quand je tente de créer un parent de l'enfant par exemple sub.build_client la clé étrangère n'est pas définie, par ex.

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

Il fonctionne si je 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 

Ive a passé 3 heures et tripoter a nulle part. Quelqu'un peut-il expliquer ce que je fais mal, les choses à vérifier etc

Répondre

9

Selon vos associations de modèles, un Subscription est un enfant de Client. Si vous créez d'abord un abonnement, puis créez un client selon votre premier exemple, Rails n'a aucun moyen de définir une valeur de clé étrangère client_id dans la table subscriptions car vous n'avez pas créé l'enregistrement client à ce stade. il n'y a rien à associer à l'abonnement. C'est pourquoi vous devez d'abord créer l'enregistrement parent (c'est-à-dire un client), puis l'associer à un enregistrement d'abonnement enfant à l'aide de la méthode build_subscription.

+0

merci John, je pensais que c'était le cas (j'ai consulté le guide des rails mais je n'ai pas trouvé cela expliqué, donc je voulais confirmer ici sur stackoverflow). Mais comment se fait avec un has_many appartient à la relation que cela peut être fait. – robodisco

+0

Je pensais juste que si ça ne peut pas être fait, pourquoi est la méthode de construction là? Si le foreign_id ne peut pas être défini quelle est l'utilisation de cette méthode dans cette relation? – robodisco

+1

C'est une bonne question. –

1

Dans mes projets j'ai de nombreuses associations similaires, mais je défends souvent la mise en client_id null, donc je ne peux pas créer un objet enfant sans objet parent.

Essayez:

sub = Subscription.new 
sub.build_client 
sub.save 

Il va créer et enregistrer les deux objets.

0

Dans l'un des commentaires, vous demandez pourquoi la méthode build_client est présente. Lorsque vous enregistrez le client, puis vérifiez la client_id sur la sous, il est nul, mais si vous auriez aussi appelé

sub.save(validate: false) 

puis vérifié la client_id sur la sous, il existerait. Donc, bien qu'il ait fallu une sauvegarde supplémentaire, il fait toujours la magie de la configuration de la clé étrangère pour sub.

1

Cela semble avoir été corrigé dans Rails 4.2.5 ou antérieur. (Je ne suis pas sûr de la version la plus ancienne avec le correctif.J'ai seulement testé 4.2.5.)

Lorsque le parent est enregistré, après que l'enregistrement parent est inséré, une mise à jour est automatiquement exécutée pour ajouter le ID parent à l'enregistrement enfant.

Cependant, je n'ai trouvé aucune documentation sur ce comportement, le code pertinent, ou les tests automatisés, donc je ne suis pas sûr s'il a été intentionnellement corrigé et ce comportement devrait être invoqué. Il serait peut-être préférable de rester avec les solutions dans les autres réponses ici.

Cela semble également être encore cassé pour has_many dans Rails 4.2.5.

Questions connexes