Rails: mettre à jour l'attribut du modèle sans appeler les rappels

J'ai un modèle utilisateur qui a un attribut: credits. Je veux un bouton simple qui ajoutera 5 aux crédits de l'utilisateur, à travers une route appelée "add" de sorte que /users/3/add ajouterait 5 aux crédits de user id = 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, je ne veux pas appeler @user.enregistrer parce que j'ai un rappel before_save Qui re-crypte le mot de passe de l'utilisateur en fonction de l'heure UTC actuelle. Je veux juste simplement ajouter 5 à l'attribut et éviter le rappel, je n'ai jamais pensé qu'une chose aussi simple pourrait être si difficile.

Modifier:

J'ai changé le rappel en: before_create, voici mon nouveau code de contrôleur (partie):

  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

Édition 2:

Ok C'était un problème de validation qui a fait que les changements dans "EDIT" ne fonctionnaient pas, mais j'aimerais toujours une réponse à la question initiale de la mise à jour sans rappels!

60
demandé sur Sam Stern 2011-12-28 05:36:13

9 réponses

Rails 3.1 introduit update_column, qui est le même que update_attribute, mais sans déclencher de validations ou de rappels:

Http://apidock.com/rails/ActiveRecord/Persistence/update_column

117
répondu cvshepherd 2011-12-28 22:54:36

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 mélanger ceci à votre classe de base d'enregistrement actif.

Pour mettre à jour un attribut, vous pouvez utiliser update_column. En outre, il existe des méthodes spécifiques qui peuvent être trouvées dans les rails guides http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

7
répondu Matt Smith 2016-04-22 09:06:25

Je pense que vous devriez utiliser la méthode update_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
répondu DanneManne 2011-12-28 04:50:19

En réponse 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 des rappels:

@user.update_columns credits: 5, bankrupt: false  

Il y a d'autres options ici dans les Rails Guides si vous préférez, mais j'ai trouvé cette façon d'être le plus facile.

3
répondu Matt 2018-08-06 20:03:11

Vous devriez pouvoir utiliser update_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ère 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
répondu miked 2011-12-28 04:22:42
2
répondu katzmopolitan 2013-12-09 20:25:18

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. Tellement cool.

2
répondu hb922 2015-06-19 18:35:58

Peut-être que votre autre crochet before_save devrait vérifier si le mot de passe de l'Utilisateur a réellement changé avant de le chiffrer à nouveau.

1
répondu Finbarr 2011-12-28 01:41:38

Vous avez un certain nombre d'options, y compris la modification du rappel que vous utilisez, par exemple, after_create.

Vous pouvez mettre à jour des colonnes sans déclencher de rappels, voir sauter les rappels dans le guide AR. Par exemple, update_column ne déclenche pas de rappels. Le lien précédent répertorie les fonctions non déclenchantes.

Vous pouvez également utiliser l'un des formulaires de rappel conditionnel (ou même un observateur) pour savoir quand le mot de passe est modifié. Voir Activerecord::Sale, par exemple, @user.password_changed?.

1
répondu Dave Newton 2014-03-22 11:45:50