Dans le Rails 3 docs , la méthode build
d'associations est décrite comme identique à la méthode new
, mais avec l'affectation automatique de la clé étrangère, directement depuis la documentation:
Firm#clients.build (similar to Client.new("firm_id" => id))
J'ai lu pareil ailleurs.
Cependant, lorsque j’utilise new
(par exemple, some_firm.clients.new
sans paramètres), le nouveau client firm_id
_ association est créée automatiquement. Je regarde les résultats en ce moment dans la console!
Est-ce que je manque quelque chose? Les documents sont-ils un peu obsolètes (improbables)? Quelle est la différence entre build
et new
?
Vous avez mal interprété la documentation légèrement. some_firm.client.new
crée un nouvel objet Client
à partir de la collection de clients et peut donc définir automatiquement le firm_id
à some_firm.id
, alors que les docs appellent Client.new
qui n'a aucune connaissance de l'identité de l'entreprise, il a donc besoin du firm_id
passé à lui.
La seule différence entre some_firm.clients.new
et some_firm.clients.build
semble être que build
ajoute également le client nouvellement créé à la collection clients
:
henrym:~/testapp$ Rails c
Loading development environment (Rails 3.0.4)
r:001 > (some_firm = Firm.new).save # Create and save a new Firm
#=> true
r:002 > some_firm.clients # No clients yet
#=> []
r:003 > some_firm.clients.new # Create a new client
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>
r:004 > some_firm.clients # Still no clients
#=> []
r:005 > some_firm.clients.build # Create a new client with build
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>
r:006 > some_firm.clients # New client is added to clients
#=> [#<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>]
r:007 > some_firm.save
#=> true
r:008 > some_firm.clients # Saving firm also saves the attached client
#=> [#<Client id: 1, firm_id: 1, created_at: "2011-02-11 00:18:47",
updated_at: "2011-02-11 00:18:47">]
Si vous créez un objet par le biais d'une association, build
devrait être préféré à new
car la construction conserve votre objet en mémoire, some_firm
(dans ce cas) dans un état cohérent avant même que des objets aient été enregistrés dans la base de données.
build
n'est qu'un alias pour new
:
alias build new
Le code complet peut être trouvé: https://github.com/Rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74
Vous avez raison, la construction et les nouvelles fonctions ont le même effet que de définir la clé étrangère, lorsqu'elles sont appelées via une association. Je pense que la raison pour laquelle la documentation est écrite comme cela est pour préciser qu'un nouvel objet Client est en cours d'instanciation, par opposition à une nouvelle relation d'enregistrement actif. C'est le même effet qu'appeler .new sur une classe aurait pour Ruby. Cela revient à dire que la documentation précise que l'appel s'appuyant sur une association est identique, c'est créer un nouvel objet (appeler .new) et transmettre les clés étrangères à cet objet. Ces commandes sont toutes équivalentes:
Firm.first.clients.build
Firm.first.clients.new
Client.new(:firm_id => Firm.first.id)
Je pense que la raison .build existe, c'est que Firm.first.clients.new pourrait être interprété comme signifiant que vous créez un nouvel objet de relation has_many, plutôt qu'un client réel. L'appel .build est donc un moyen de clarifier cela.
build
vs new
:
la plupart du temps new et build sont identiques mais build stocke l’objet en mémoire,
par exemple:
pour les nouveaux:
Client.new(:firm_id=>Firm.first.id)
Pour construire:
Firm.first.clients.build
Ici, les clients sont stockés en mémoire. Lorsque vous enregistrez une entreprise, les enregistrements associés sont également enregistrés.
Tag.new post_id: 1
instanciera une balise avec son post_id
ensemble.
@post.tags.build
fait la même chose ET la balise instanciée sera dans @post.tags
même avant sa sauvegarde.
Ça signifie @post.save
sauvegardera les @post et les balises nouvellement construites (en supposant que: inverse_of est défini). C’est formidable, car Rails validera les deux objets avant de sauvegarder et aucun ne sera sauvegardé si l’un ou l’autre d’entre eux échoue à la validation).
@post.tags.build
et @post.tags.new
sont équivalents (au moins depuis Rails 3.2).