web-dev-qa-db-fra.com

Rails update_attributes sans sauvegarde?

Existe-t-il une alternative à update_attributes qui n'enregistre pas l'enregistrement?

Donc, je pourrais faire quelque chose comme:

@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

Au fait, je sais que je peux @car.model = 'Sierra', mais je veux les mettre à jour sur une seule ligne.

364
tybro0103

Je crois que ce que vous recherchez est assign_attributes .

C'est fondamentalement la même chose que update_attributes mais cela n'enregistre pas l'enregistrement:

_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
_
571
Ajedi32

Vous pouvez utiliser assign_attributes ou attributes= (ils sont identiques)

Aide-mémoire sur les méthodes de mise à jour (pour Rails 4):

  • update_attributes = assign_attributes + save
  • attributes= = alias de assign_attributes
  • update = alias de update_attributes

Source:
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

Un autre aide-mémoire:
http://www.davidverhasselt.com/set-attributes-in-activerecord/#cheat-sheet

159
Yarin

Vous pouvez utiliser la méthode 'attributs':

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

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

attributs = (new_attributes, guard_protected_attributes = true) Vous permet de définir tous les attributs à la fois en transmettant un hachage avec les clés correspondant aux noms d'attribut (qui à nouveau correspond aux noms de colonne).

Si guard_protected_attributes est à true (valeur par défaut), les attributs sensibles peuvent être protégés de cette forme d’affectation en masse à l’aide de la macro attr_protected. Vous pouvez également spécifier quels attributs sont accessibles avec la macro attr_accessible. Ensuite, tous les attributs qui ne sont pas inclus dans cette liste ne pourront pas être affectés en masse.

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
63
bruno077

Pour affecter en masse des valeurs à un modèle ActiveRecord sans enregistrer, utilisez les méthodes assign_attributes ou attributes=. Ces méthodes sont disponibles dans Rails 3 et plus récent. Cependant, il existe des différences mineures et des pièges liés à la version à connaître.

Les deux méthodes suivent cet usage:

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

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

Notez qu'aucune des méthodes n'effectuera de validation ni d'exécuter des rappels. les rappels et la validation se produiront lorsque save sera appelé.

Rails 3

attributes= diffère légèrement de assign_attributes dans Rails 3. attributes= vérifie que l'argument qui lui est transmis est un hachage et retourne immédiatement s'il ne l'est pas. assign_attributes n'a pas cette vérification de hachage. Consultez la documentation de l'API ActiveRecord Attribute Assignment) pour attributes= .

Le code non valide suivant échouera silencieusement en renvoyant simplement sans définir les attributs:

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

attributes= se comportera silencieusement comme si les assignations avaient été effectuées avec succès, alors qu'en réalité, elles ne l'étaient pas.

Ce code non valide lève une exception lorsque assign_attributes tente de hiérarchiser les clés de hachage du tableau englobant:

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

assign_attributes lève une exception NoMethodError pour stringify_keys, indiquant que le premier argument n'est pas un hachage. L'exception elle-même n'est pas très informative sur la cause réelle, mais le fait qu'une exception se produise est très très important.

La seule différence entre ces cas est la méthode utilisée pour l'affectation en masse: attributes= réussit silencieusement et assign_attributes lève une exception pour informer qu'une erreur s'est produite.

Ces exemples peuvent sembler artificiels, et ils le sont dans une certaine mesure, mais ce type d'erreur peut facilement se produire lors de la conversion de données à partir d'une API, ou même simplement lors de l'utilisation d'une série de transformation de données et en oubliant de Hash[] les résultats du résultat final. .map. Conservez un code 50 lignes ci-dessus et 3 fonctions supprimées de votre attribut, et vous aurez la recette de l'échec.

La leçon avec Rails 3 est la suivante: toujours utilisez assign_attributes au lieu de attributes=.

Rails 4

Dans Rails 4, attributes= est simplement un alias de assign_attributes. Consultez la documentation de l'API ActiveRecord Attribute Assignment) pour attributes= .

Avec Rails 4, l'une ou l'autre méthode peut être utilisée de manière interchangeable. Si le premier argument n'est pas passé avec le hachage, une exception très utile s'ensuivra: ArgumentError: When assigning attributes, you must pass a hash as an argument.

Validations

Si vous êtes en train de préparer des affectations en vue d'une save, vous voudrez peut-être aussi valider avant la sauvegarde. Vous pouvez utiliser les méthodes valid? et invalid? pour cela. Les deux renvoient des valeurs booléennes. valid? renvoie true si le modèle non enregistré passe toutes les validations ou false s'il ne le fait pas. invalid? est simplement l'inverse de valid?

valid? peut être utilisé comme ceci:

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

Cela vous donnera la possibilité de gérer tout problème de validation avant d'appeler save.

8
Michael Gaskill