As diferenças entre .build, .create e .create! e quando eles devem ser usados?

167

Então, eu tenho visto pessoas usando .build, .create e .create! nos controladores cada vez mais ultimamente. Qual é a diferença de apenas usar .new e passig o objeto param'd e depois .save? Existem prós e contras? O uso desses outros métodos oferece benefícios?

Tim Knight
fonte

Respostas:

234

Existem algumas diferenças, mas elas não são grandes:

  1. .createé equivalente a .newseguido por .save. É apenas mais sucinto.
  2. .create!é equivalente a .newseguido por.save! (gera um erro se o salvamento falhar). Também é um pouquinho mais curto
  3. Eu acho que .buildé principalmente um apelido para .new. Ele funciona de uma maneira no Rails 3 e uma outra maneira em Rails <3.x

A parte mais importante, no entanto, é que esses métodos podem ser chamados por meio de uma associação ( has_many, etc.) para vincular automaticamente os dois modelos.

zenazn
fonte
1
Eu escolhi essa como a resposta mais correta por causa da menção de poder vincular os modelos associados a eles - essa é uma diferença interessante e importante que penso em usar .new e .save. O que exige um pouco de trabalho extra. Obrigado.
Tim Knight
11
Pequenos esclarecimentos sobre o 3 - build fazem um pouco mais do que apenas novos - ele também define o link da associação.
Dois Bits Gangster
116
O Build é diferente de New. Mas a diferença não é que ele define o link de associação (o New também faz isso para a nova instância). A diferença é que o Build preenche o chamador com a nova instância, mas New não. Por exemplo: Wall.posts.new fornece uma nova postagem associada ao seu Wall, mas o Wall.posts ainda está vazio após esta chamada. O Wall.posts.build fornece uma nova postagem associada ao seu Wall, e agora o seu Wall.posts tem uma postagem.
Amin Ariana
3
Não é apenas um alias agora, sem funcionalidade especial?
Gabriele Cirulli 8/08/13
14
No Rails 4, acabei de fazer o check-in no console. wall.posts.new e wall.posts.build estão preenchendo o objeto wall da mesma maneira. Significa que após wall.posts.new, wall.posts não está vazio conforme reivindicado no comentário de Amin.
Bot
35

Embora seja correto que createchama newe, em seguida, savehá uma grande diferença entre as duas alternativas em seus valores de retorno.

Saveretorna um trueou falsedependendo se o objeto foi salvo com sucesso no banco de dados ou não. Isso pode ser usado para controle de fluxo, conforme o primeiro exemplo da pergunta acima.

Createretornará o modelo independentemente de o objeto ter sido salvo ou não. Isso tem implicações para o código acima, pois a ramificação superior da ifinstrução sempre será executada mesmo se o objeto falhar nas validações e não for salvo.

Se você usa createa lógica de ramificação, corre o risco de falhas silenciosas, o que não é o caso se você usar new+ save.

create! não sofre do mesmo problema que gera e exceção se o registro for inválido.

A createalternativa pode ser útil em controladores onde respond_withé usado para respostas de API (JSON / XML). Nesse caso, a existência de erros no objeto fará com que os erros sejam retornados na resposta com um status de unprocessable_entity, que é exatamente o que você deseja de uma API.

Eu sempre usaria a opção new+ savepara html, especialmente se você estiver contando com o valor de retorno para controle de fluxo.

nmott
fonte
6

#create é uma versão mais curta do novo e salva. #crio! está lançando uma exceção se a validação não for positiva.

rkj
fonte
5

Eu segundo as respostas acima. Além disso create, não se pode passar falsecomo argumento com o qual você pode fazer save. Passar falsecomo argumento ignorará todas as validações de trilhos

Vineeth Pradhan
fonte