Rails: update_attribute vs update_attributes

255
Object.update_attribute(:only_one_field, "Some Value")
Object.update_attributes(:field1 => "value", :field2 => "value2", :field3 => "value3")

Ambos atualizarão um objeto sem precisar informar explicitamente o AR para atualizar.

A API do Rails diz:

para update_attribute

Atualiza um único atributo e salva o registro sem passar pelo procedimento de validação normal. Isso é especialmente útil para sinalizadores booleanos em registros existentes. O método update_attribute regular no Base é substituído por esse quando o módulo de validações é misturado, o que é por padrão.

para update_attributes

Atualiza todos os atributos do Hash passado e salva o registro. Se o objeto for inválido, o salvamento falhará e falso será retornado.

Portanto, se não quiser validar o objeto, devo usar o update_attribute. E se eu tiver essa atualização em um before_save, ele fará o stackoverflow?

Minha pergunta é: update_attribute também ignora o antes de salvar ou apenas a validação.

Além disso, qual é a sintaxe correta para passar um hash para update_attributes ... confira meu exemplo na parte superior.

thenengah
fonte
Por que você deseja colocar uma update_attributedeclaração dentro de um before_saveretorno de chamada? Não consigo pensar em uma boa razão para isso.
Daniel Pietzsch
1
Eu tenho objetos que precisam ser atualizados com base na quantidade do objeto atualizado. Qual é a melhor maneira?
thenengah
Estou certo de que os objetos que você precisa atualizar são atributos do objeto que você está salvando? Se sim, você pode configurá-las e elas serão atualizadas juntamente com o objeto salvo de qualquer maneira (porque elas são definidas em um before_saveretorno de chamada). Fe em vez de update_attribute(:discount, 0.1) if amount > 100você poderia fazer discount = 0.1 if amount > 100. update_attributechama saveo objeto, o que é desnecessário nesse caso, pois a instrução está dentro de um before_saveretorno de chamada e será salva de qualquer maneira. Espero que faça sentido.
Daniel Pietzsch
Sim e não. No entanto, o status dos objetos aos quais você está se referindo depende de outras condições que não podem ser processadas antes do salvamento.
thenengah
3
como uma nota, a validação desses métodos desvia, mas vai continuar a efectuar chamadas de retorno, como after_save ...
rogerdpack

Respostas:

328

Por favor, consulte update_attribute. Ao clicar em show source, você receberá o código a seguir

      # File vendor/rails/activerecord/lib/active_record/base.rb, line 2614
2614:       def update_attribute(name, value)
2615:         send(name.to_s + '=', value)
2616:         save(false)
2617:       end

e agora consulte update_attributese veja o código que você obtém

      # File vendor/rails/activerecord/lib/active_record/base.rb, line 2621
2621:       def update_attributes(attributes)
2622:         self.attributes = attributes
2623:         save
2624:       end

a diferença entre dois é update_attributeusos save(false)enquanto update_attributesusos saveou você pode dizer save(true).

Desculpe pela descrição longa, mas o que quero dizer é importante. save(perform_validation = true), se perform_validationfor falso, ignora (ignora a palavra apropriada) todas as validações associadas save.

Para segunda pergunta

Além disso, qual é a sintaxe correta para passar um hash para update_attributes ... confira meu exemplo na parte superior.

Seu exemplo está correto.

Object.update_attributes(:field1 => "value", :field2 => "value2", :field3 => "value3")

ou

Object.update_attributes :field1 => "value", :field2 => "value2", :field3 => "value3"

ou se você obtiver todos os campos de dados e nome em um hash, diga params[:user]aqui, use apenas

Object.update_attributes(params[:user])
Salil
fonte
7
Sua declaração sobre retornos de chamada está incorreta, pelo menos em Rails 3. Diz claramente nos comentários na fonte que "os retornos de chamada são invocados".
Batkins
Eu segundo o @Batkins diz
Raf
3
@Batkins ainda validações não são executados - que é a parte mais importante :)
Tigraine
1
Os links acima não são mais precisos, pelo menos a partir do Rails 5.1 . Esses métodos foram movidos para ActiveRecord :: Persistence. Você pode encontrar as informações atualizadas aqui: atributo de atualização e aqui update_attributes Nota: update_attributesagora é um apelido paraupdate
tgf
74

Dica: update_attribute está sendo descontinuado no Rails 4 através do Commit a7f4b0a1 . Remove a update_attributefavor de update_column.

Matt
fonte
45
Isso não é mais verdade; o método foi adicionado novamente. Veja github.com/rails/rails/pull/6738#issuecomment-39584005
Dennis
20
update_attributepula validação, mas respeita chamadas de retorno, update_columnirá saltar tanto validação e chamadas de retorno e rotina de actualização :updated_at, updateé a função normal que vão respeitar os dois retornos e validação
Mohammad AbuShady
2
eles já vão se decidir. reset_column, update_column também foi descontinuado.
precisa saber é o seguinte
2
update_columnnão é preterido, mas update_columns(name: value)é favorecido. reset_columnfoi removido.
onebree
15

update_attribute

Este método atualiza o atributo único do objeto sem chamar a validação baseada em modelo.

obj = Model.find_by_id(params[:id])
obj.update_attribute :language, java

update_attributes

Esse método atualiza vários atributos de um único objeto e também passa na validação baseada em modelo.

attributes = {:name => BalaChandar”, :age => 23}
obj = Model.find_by_id(params[:id])
obj.update_attributes(attributes)

Espero que esta resposta esclareça quando usar qual método de registro ativo.

Balachandar1887229
fonte
12

Também é importante notar que update_attribute, com , o atributo desejado a ser atualizado não precisa estar na lista branca attr_accessiblepara atualizá-lo, em oposição ao método de atribuição em massa, update_attributesque atualizará apenas os attr_accessibleatributos especificados.

Kibet Yegon
fonte
8

update_attributesimplesmente atualiza apenas um atributo de um modelo, mas podemos passar vários atributos no update_attributesmétodo

Exemplo:

user = User.last

#update_attribute
user.update_attribute(:status, "active")

Passa na validação

#update_attributes
user.update_attributes(first_name: 'update name', status: "active")

não é atualizado se a validação falhar.

Shoaib Malik
fonte
Muito bem explicado. Obrigado!
Diego Somar
6

Ótimas respostas. observe que quanto ao ruby ​​1.9 e acima, você poderia (e acho que deveria) usar a nova sintaxe de hash para update_attributes:

Model.update_attributes(column1: "data", column2: "data")
Ziv Galili
fonte
6

Você pode estar interessado em visitar este post do blog sobre todas as formas possíveis de atribuir um atributo ou atualizar um registro (atualizado para o Rails 4) update_attribute, update, update_column, update_columns etc. http://www.davidverhasselt.com/set-attributes-in-activerecord/ . Por exemplo, ele difere em aspectos como executar validações, tocar em updated_at do objeto ou acionar retornos de chamada.

Como resposta à pergunta do OP, update_attributenão passa retornos de chamada.

adamliesko
fonte
Sim, eu modifiquei a resposta. Obrigado pelo feedback.
adamliesko
4

update_attributee update_attributessão semelhantes, mas com uma grande diferença: update_attribute não executa validações.

Além disso:

  • update_attributeé usado para atualizar o registro com atributo único .

    Model.update_attribute(:column_name, column_value1)
  • update_attributesé usado para atualizar o registro com vários atributos.

    Model.update_attributes(:column_name1 => column_value1, :column_name2 => column_value2, ...)

Esses dois métodos são realmente fáceis de confundir, devido a nomes e trabalhos semelhantes. Portanto, update_attributeestá sendo removido em favor de update_column.

Agora, no Rails4, você pode usar Model.update_column(:column_name, column_value)no local deModel.update_attribute(:column_name, column_value)

Clique aqui para obter mais informações sobre update_column.

uma
fonte
4

Para responder à sua pergunta, update_attributepule as "validações" de pré-salvamento, mas ele ainda executa outros retornos de chamada como after_saveetc. Portanto, se você realmente quiser "apenas atualizar a coluna e pular qualquer crupto AR", precisará usar (aparentemente)

Model.update_all(...)consulte https://stackoverflow.com/a/7243777/32453

rogerdpack
fonte
2

Recentemente, me deparei com problemas de update_attributevs. update_attributese validação, nomes tão semelhantes, comportamentos tão diferentes, tão confusos.

Para passar o hash update_attributee ignorar a validação, você pode:

object = Object.new
object.attributes = {
  field1: 'value',
  field2: 'value2',
  field3: 'value3'
}
object.save!(validate: false)
Wojciech Bednarski
fonte
1

Acho que sua pergunta é se ter um update_attribute em um before_save levará a um loop infinito (de chamadas update_attribute em retornos de chamada before_save, originalmente acionadas por uma chamada update_attribute)

Tenho certeza de que ignora o retorno de chamada before_save, pois na verdade não salva o registro. Você também pode salvar um registro sem acionar validações usando

Model.save false

concept47
fonte