Rails update_attributes sem salvar?

386

Existe uma alternativa para update_attributes que não salva o registro?

Então eu poderia fazer algo como:

@car = Car.new(:make => 'GMC')
#other processing
@car.update_attributes(:model => 'Sierra', :year => "2012", :looks => "Super Sexy, wanna make love to it")
#other processing
@car.save

BTW, eu sei que posso @car.model = 'Sierra', mas quero atualizá-los todos em uma linha.

tybro0103
fonte
o que você quer dizer com "não salvar o registro"?
Anatoly
update_attributes salva o modelo no banco de dados. Gostaria de saber se existe um método semelhante que não existe.
tybro0103
3
atributos método não destrutivo. Veja a API para obter detalhes
Anatoly
3
Você pode usar update_column (nome, valor) Atualiza um único atributo de um objeto, sem chamar save. 1. A validação é ignorada. 2. Os retornos de chamada são ignorados. 3. a coluna updated_at / updated_on não será atualizada se essa coluna estiver disponível. apidock.com/rails/ActiveRecord/Persistence/update_column
Antoine
10
Para o 3.1+, use assign_attributes apidock.com/rails/ActiveRecord/Base/assign_attributes
elado

Respostas:

597

Eu acredito que você está procurando assign_attributes.

É basicamente o mesmo que update_attributes, mas não salva o registro:

class User < ActiveRecord::Base
  attr_accessible :name
  attr_accessible :name, :is_admin, :as => :admin
end

user = User.new
user.assign_attributes({ :name => 'Josh', :is_admin => true }) # Raises an ActiveModel::MassAssignmentSecurity::Error
user.assign_attributes({ :name => 'Bob'})
user.name        # => "Bob"
user.is_admin?   # => false
user.new_record? # => true
Ajedi32
fonte
O seu exemplo é um pouco enganador, pois você não ter colado esta linha do modelo: attr_accessible :is_admin, :as => :admin;)
Robin
@Robin Ou simplesmente: attr_protected :is_admin. Ou: attr_accessible :nameo ponto é que, neste exemplo,: is_admin está protegido. Devo também observar que a tentativa de atribuir em massa um atributo protegido .assign_attributesrealmente gera um ActiveModel::MassAssignmentSecurity::Error, mesmo que isso não seja mostrado no exemplo.
precisa saber é o seguinte
Sim, mas minha linha é do documento ao qual você vinculou. Só estou dizendo que você deveria ter copiado / colado o exemplo inteiro. Mas sim, você pode apenas dizer que está protegido.
Robin
@ Robin Vou atualizar o exemplo para ser um pouco mais específico. O exemplo nos documentos também é um pouco enganador, pois não menciona que user.assign_attributes({ :name => 'Josh', :is_admin => true })gera uma mensagem de erro e na verdade não define a propriedade de nome do usuário.
precisa saber é o seguinte
7
O assign_attributes está disponível no Rails 3.1 em diante, portanto você não poderá usá-lo se ainda estiver executando uma versão antiga do Rails.
Haegin 6/12/12
174

Você pode usar assign_attributesou attributes=(eles são iguais)

Folha de dicas dos métodos de atualização (para Rails 6):

  • update= assign_attributes+save
  • attributes= = apelido de assign_attributes
  • update_attributes = obsoleto, apelido de update

Fonte:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_assignment .rb

Outra folha de dicas:
http://www.davidverhasselt.com/set-attributes-in-activerecord/#cheat-sheet

Yarin
fonte
11
Claro e curto. Obrigado.
Freemanoid # 15/14
11
no caso. Mas assign_attributes não se comporta assim.
ClassyPimp
65

Você pode usar o método 'attribute':

@car.attributes = {:model => 'Sierra', :years => '1990', :looks => 'Sexy'}

Fonte: http://api.rubyonrails.org/classes/ActiveRecord/Base.html

attribute = (new_attributes, guard_protected_attributes = true) Permite definir todos os atributos de uma só vez passando um hash com chaves correspondentes aos nomes dos atributos (que novamente correspondem aos nomes das colunas).

Se guard_protected_attributes for true (o padrão), os atributos sensíveis poderão ser protegidos dessa forma de atribuição em massa usando a macro attr_protected. Ou, como alternativa, você pode especificar quais atributos podem ser acessados ​​com a macro attr_accessible. Em seguida, todos os atributos não incluídos nos que não serão permitidos serão atribuídos em massa.

class User < ActiveRecord::Base
  attr_protected :is_admin
end

user = User.new
user.attributes = { :username => 'Phusion', :is_admin => true }
user.username   # => "Phusion"
user.is_admin?  # => false

user.send(:attributes=, { :username => 'Phusion', :is_admin => true }, false)
user.is_admin?  # => true
bruno077
fonte
7

Para atribuição em massa de valores a um modelo ActiveRecord sem salvar, use os métodos assign_attributesou attributes=. Esses métodos estão disponíveis no Rails 3 e mais recentes. No entanto, existem pequenas diferenças e dicas relacionadas à versão a serem observadas.

Ambos os métodos seguem esse uso:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }

@user.attributes = { model: "Sierra", year: "2012", looks: "Sexy" }

Observe que nenhum dos métodos realizará validações ou executará retornos de chamada; retornos de chamada e validação acontecerão quando savefor chamado.

Trilhos 3

attributes=difere um pouco do assign_attributesRails 3. attributes=irá verificar se o argumento passado para ele é um Hash e retorna imediatamente se não for; assign_attributesnão tem essa verificação de hash. Consulte a documentação da API ActiveRecord Attribute Assignment paraattributes= .

O seguinte código inválido falhará silenciosamente retornando sem definir os atributos:

@user.attributes = [ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ]

attributes= comportará silenciosamente como se as designações tivessem sido feitas com sucesso, quando na verdade não eram.

Este código inválido gerará uma exceção ao assign_attributestentar especificar as chaves hash da matriz anexa:

@user.assign_attributes([ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ])

assign_attributesirá gerar uma NoMethodErrorexceção para stringify_keys, indicando que o primeiro argumento não é um Hash. A exceção em si não é muito informativa sobre a causa real, mas o fato de ocorrer uma exceção é muito importante.

A única diferença entre esses casos é o método usado para atribuição em massa: attributes=silenciosamente é bem-sucedido e assign_attributesgera uma exceção para informar que ocorreu um erro.

Esses exemplos podem parecer inventados, e são até certo ponto, mas esse tipo de erro pode ocorrer facilmente ao converter dados de uma API, ou mesmo usando uma série de transformação de dados e esquecendo Hash[]os resultados da final .map. Mantenha algum código de 50 linhas acima e 3 funções removidas da atribuição de atributo, e você terá uma receita para a falha.

A lição do Rails 3 é esta: sempre use em assign_attributesvez de attributes=.

Trilhos 4

No Rails 4, attributes=é simplesmente um apelido para assign_attributes. Consulte a documentação da API ActiveRecord Attribute Assignment paraattributes= .

Com o Rails 4, qualquer um dos métodos pode ser usado de forma intercambiável. A falha em passar um Hash como o primeiro argumento resultará em uma exceção muito útil:ArgumentError: When assigning attributes, you must pass a hash as an argument.

Validações

Se você estiver executando tarefas de pré-vôo em preparação para a save, também poderá estar interessado em validar antes de salvar. Você pode usar os métodos valid?e invalid?para isso. Ambos retornam valores booleanos. valid?retorna true se o modelo não salvo passa em todas as validações ou false se não passa. invalid?é simplesmente o inverso devalid?

valid? pode ser usado assim:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }.valid?

Isso permitirá que você lide com qualquer problema de validação antes de ligar save.

Michael Gaskill
fonte