web-dev-qa-db-fra.com

Construire vs nouveau dans Rails 3

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?

123
ClosureCowboy

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.

207
henrym

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

89
Hatem Mahmoud

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.

11
Pan Thomakos

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.

4
Sarwan Kumar

Modèle.nouveau

Tag.new post_id: 1 instanciera une balise avec son post_id ensemble.

@ model.models.new

@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).

models.new vs models.build

@post.tags.build et @post.tags.new sont équivalents (au moins depuis Rails 3.2).

2
tybro0103