web-dev-qa-db-fra.com

Rails 3 vérifie si l'attribut a changé

Besoin de vérifier si un bloc d'attributs a été modifié avant la mise à jour dans Rails 3.

rue1, rue2, ville, état, code postal

Je sais que je pourrais utiliser quelque chose comme

if @user.street1 != params[:user][:street1]
  then do something....
end

Mais ce morceau de code sera VRAIMENT long. Y a-t-il un moyen plus propre?

147
pcasa

Départ ActiveModel :: Dirty (disponible sur tous les modèles par défaut). La documentation est vraiment bonne, mais elle vous permet de faire des choses telles que:

@user.street1_changed? # => true/false
273
Peter Brown

Voici comment j'ai résolu le problème de la vérification des modifications d'attributs multiples.

attrs = ["street1", "street2", "city", "state", "zipcode"]

if (@user.changed & attrs).any?
  then do something....
end

La méthode changed renvoie un tableau des attributs modifiés pour cet objet.

Tous les deux @user.changed et attrs sont des tableaux pour que je puisse obtenir l’intersection (voir ary & other ary méthode). Le résultat de l'intersection est un tableau. En appelant any? sur le tableau, je deviens vrai s’il ya au moins une intersection.

Aussi très utile, le changed_attributes la méthode retourne un hachage des attributs avec leurs valeurs originales et le changes renvoie un hachage des attributs avec leurs valeurs originales et nouvelles (dans un tableau).

Vous pouvez vérifier APIDock pour quelles versions ont pris en charge ces méthodes.

http://apidock.com/Rails/ActiveModel/Dirty

53
campeterson

ActiveModel::Dirty N'a pas fonctionné pour moi car la @model.update_attributes() a masqué les modifications. Voici comment j'ai détecté le changement dans une méthode update dans un contrôleur:

def update
  @model = Model.find(params[:id])
  detect_changes

  if @model.update_attributes(params[:model])
    do_stuff if attr_changed?
  end
end

private

def detect_changes
  @changed = []
  @changed << :attr if @model.attr != params[:model][:attr]
end

def attr_changed?
  @changed.include :attr
end

Si vous essayez de détecter un grand nombre de changements d'attributs, cela pourrait devenir compliqué. Ne devrait probablement pas faire cela dans un contrôleur, mais meh.

14
hamstar

Pour Rails 5.1+ rappels

Pour améliorer ce post et compléter d'autres réponses

La première réponse sera déconseillée pour les rappels lors de la prochaine Rails versions (après la version 5.1).
La nouvelle façon de vérifier si un attribut a changé est donc: saved_change_to_attribute?

Tu peux faire:

@user.saved_change_to_street1? # => true/false

Vous pouvez voir plus d'exemples ici sur ce blog

5
Lucas Andrade

Les réponses ci-dessus sont meilleures, mais pour la connaissance, nous avons également une autre approche: la valeur de la colonne 'catagory' est modifiée pour un objet (@design),

@design.changes.has_key?('catagory')

Les .changes renverront un hachage avec key comme nom de colonne et des valeurs sous forme de tableau avec deux valeurs [old_value, new_value] pour chaque colonne. Par exemple, la catégorie pour ci-dessus est remplacée par "ABC" par "XYZ" de @design,

@design.changes   # => {} 
@design.catagory = 'XYZ'
@design.changes # => { 'catagory' => ['ABC', 'XYZ'] }

Pour les références changement de ROR

2
shubham mishra