J'ai un modèle utilisateur qui a un attribut: credits. Je veux un simple bouton qui ajoutera 5 aux crédits de l'utilisateur, via une route appelée "ajouter" afin que/users/3/add ajoute 5 aux crédits de l'id utilisateur = 3.
def add
@user = User.find(params[:id])
@user.credits += 5
redirect_to root_path
end
C'est la partie pertinente de mon contrôleur. Le problème est que je ne veux pas appeler @ user.save car j'ai un rappel before_save qui rechiffre le mot de passe de l'utilisateur en fonction de l'heure UTC actuelle. Je veux simplement ajouter 5 à l'attribut et éviter le rappel, je n'ai jamais pensé qu'une chose aussi simple pouvait être aussi difficile.
MODIFIER:
J'ai changé le rappel en: before_create, voici mon nouveau code de contrôleur (partie pertinente):
def add
@user = User.find(params[:id])
@user.add_credits(5)
@user.save
flash[:success] = "Credits added!"
redirect_to root_path
end
et voici mon code dans le modèle:
def add_credits(num)
self.credits = num
end
EDIT 2:
Ok c'était un problème de validation qui a fait que les changements dans "EDIT" ne fonctionnaient pas, mais j'aimerais quand même une réponse à la question d'origine de la mise à jour sans rappels!
Introduction de Rails 3.1 update_column
, qui est identique à update_attribute
, mais sans déclencher de validations ni de rappels:
http://apidock.com/Rails/ActiveRecord/Persistence/update_column
Pour mettre à jour plusieurs attributs sans rappels, vous pouvez utiliser update_all dans votre modèle comme suit:
self.class.update_all({name: value, name: value}, self.class.primary_key => id)
Si vous voulez vraiment, vous pouvez même essayer même une méthode update_columns et la mélanger à votre classe de base d'enregistrement active.
Pour mettre à jour un attribut, vous pouvez utiliser update_column. De plus, il existe des méthodes spécifiques qui peuvent être trouvées dans les Rails http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
En règle générale, dans Rails 4, c'est un moyen simple de mettre à jour les attributs sans déclencher de rappels:
@user.update_column 'credits', 5
Si vous devez mettre à jour plusieurs attributs sans déclencher de rappel:
@user.update_columns credits: 5, bankrupt: false
Il existe d'autres options ici dans les Rails Guides si vous préférez, mais j'ai trouvé que cette façon était la plus simple.
Je pense que vous devriez utiliser la méthode pdate_counters dans ce cas. Utilisez-le comme ceci dans votre action de contrôleur:
def add
User.update_counters params[:id], :credits => 5
redirect_to root_path
end
Quelques options pour savoir comment faire cela dans Rails4 http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
Vous devriez pouvoir utiliser pdate_all pour éviter de déclencher des rappels.
def add
@user = User.find(params[:id])
User.where(:id=>@user.id).update_all(:credits => @user.credits+5)
redirect_to root_path
end
Je préférerais mettre cette logique dans le modèle, mais cela devrait fonctionner pour résoudre votre problème d'origine comme spécifié dans le contrôleur.
Pour mongoid, j'ai fini par utiliser http://mongoid.org/en/mongoid/docs/persistence.html Plus précisément, vous pouvez utiliser:
person.set(name:"Robert Pulson")
et aucun rappel ne sera émis. Trop cool.
Peut-être que votre autre hook before_save devrait vérifier si le mot de passe de l'utilisateur a réellement changé avant de le crypter à nouveau.
Vous disposez d'un certain nombre d'options, notamment la modification du rappel que vous utilisez, par exemple after_create
.
Vous pouvez mettre à jour les colonnes sans déclencher de rappels, voir Ignorer les rappels dans le guide AR. Par exemple, update_column
ne déclenche pas de rappel. Le lien précédent répertorie les fonctions non déclencheuses.
Vous pouvez également utiliser l'un des formulaires rappel conditionnel (ou même un observateur) lorsque le mot de passe est modifié. Voir ActiveModel :: Dirty , par exemple, @user.password_changed?
.
Vous pouvez mettre à jour une colonne en procédant ainsi
User.where (nom: 'lily') .update_all (âge: '10')