web-dev-qa-db-fra.com

Rails: mettre à jour l'attribut de modèle sans invoquer de rappels

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!

67
Sam Stern

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

130
cvshepherd

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

7
Matt Smith

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.

4
Matt

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
3
DanneManne

Quelques options pour savoir comment faire cela dans Rails4 http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

2
katzmopolitan

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.

2
miked

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.

2
hb922

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.

1
Finbarr

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?.

1
Dave Newton

Vous pouvez mettre à jour une colonne en procédant ainsi

User.where (nom: 'lily') .update_all (âge: '10')

0
Abdul Monam