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