Les différences entre .build, .create et .create! et quand doivent-ils être utilisés?

167

J'ai donc été voir les personnes qui utilisent .build, .createet au .create!sein de leurs contrôleurs de plus en plus ces derniers temps. Quelle est la différence entre simplement utiliser .newet passer l'objet paramétré et ensuite .save? Y a-t-il des avantages et des inconvénients? L'utilisation de ces autres méthodes offre-t-elle des avantages?

Tim Knight
la source

Réponses:

234

Il y a quelques différences, mais elles ne sont pas grandes:

  1. .createéquivaut à .newsuivi de .save. C'est juste plus succinct.
  2. .create!équivaut à .newsuivi de .save!(renvoie une erreur si l'enregistrement échoue). C'est aussi juste un peu plus court
  3. Je pense que .buildc'est surtout un alias pour .new. Cela fonctionne d'une manière dans Rails 3 et d'une autre manière dans Rails <3.x

La partie la plus importante, cependant, est que ces méthodes peuvent être appelées via une association ( has_many, etc.) pour lier automatiquement les deux modèles.

Zenazn
la source
1
J'ai choisi celle-ci comme la réponse la plus correcte en raison de la mention de la possibilité de lier les modèles associés avec eux - c'est une différence intéressante et importante que je pense par rapport à l'utilisation de .new et .save. Ce qui demande un peu de travail supplémentaire. Merci.
Tim Knight
11
Une clarification mineure sur 3 - build fait un peu plus que simplement nouveau - il établit également le lien d'association.
Two Bit Gangster
116
Build est différent de New. Mais la différence n'est pas qu'il définit le lien d'association (New le fait aussi pour la nouvelle instance). La différence est que Build remplit l'appelant avec la nouvelle instance, mais pas New. Par exemple: Wall.posts.new vous donne un nouveau post associé à votre Wall, mais Wall.posts est toujours vide après cet appel. Wall.posts.build vous donne un nouvel article associé à votre mur, et votre Wall.posts contient maintenant un article.
Amin Ariana
3
N'est-ce pas juste un alias maintenant, sans fonctionnalité particulière?
Gabriele Cirulli
14
Dans Rails 4, je viens de vérifier la console. wall.posts.new et wall.posts.build peuplent tous les deux l'objet mur exactement de la même manière. Signifie qu'après wall.posts.new, wall.posts n'est pas vide comme le prétend le commentaire d'Amin.
Bot
35

Bien qu'il soit correct que les createappels newet puis saveil y a une grande différence entre les deux alternatives dans leurs valeurs de retour.

Saverenvoie l'un trueou l' autre falseselon que l'objet a été enregistré avec succès dans la base de données ou non. Cela peut ensuite être utilisé pour le contrôle de flux selon le premier exemple de la question ci-dessus.

Createrenverra le modèle, que l'objet ait été enregistré ou non. Cela a des implications pour le code ci-dessus en ce que la branche supérieure de l' ifinstruction sera toujours exécutée même si l'objet échoue aux validations et n'est pas enregistré.

Si vous utilisez createavec une logique de branchement, vous risquez des échecs silencieux, ce qui n'est pas le cas si vous utilisez new+ save.

create! ne souffre pas du même problème qu'il soulève et exception si l'enregistrement n'est pas valide.

L' createalternative peut être utile dans les contrôleurs où respond_withest utilisée pour les réponses API (JSON / XML). Dans ce cas, l'existence d'erreurs sur l'objet entraînera le renvoi des erreurs dans la réponse avec un statut de unprocessable_entity, qui est exactement ce que vous attendez d'une API.

J'utiliserais toujours l' option new+ savepour html, surtout si vous comptez sur la valeur de retour pour le contrôle de flux.

nmott
la source
6

#create est une version plus courte de new and save. #créer! lève une exception si la validation n'était pas positive.

rkj
la source
5

Je seconderais les réponses ci-dessus. De plus create, on ne peut pas passer falsepour un argument avec lequel on peut faire save. Passer falsecomme argument sautera toutes les validations de rails

Vineeth Pradhan
la source