10
votes

Existe-t-il un moyen d'empêcher les attributs sérialisés dans les rails de se mettre à jour même s'il n'y a pas de changements?

Ceci est probablement l'une des choses que tous les nouveaux utilisateurs découvrent les rails plus tôt ou ultérieurs. Je viens de réaliser que les rails mettent à jour tous les champs avec le mot-clé Serialize, sans vérifier si quelque chose a vraiment changé à l'intérieur. D'une manière qui est la chose sensible à faire pour le cadre générique.

mais y a-t-il un moyen de remplacer ce comportement? Si je peux garder une trace si les valeurs dans un champs sérialisées ont changé ou non, est-il un moyen de l'empêcher d'être poussé dans la déclaration de mise à jour? J'ai essayé d'utiliser "update_attributes" et limiter le hachage dans les domaines d'intérêt, mais les rails mettent toujours à jour tous les champs sérialisés.

suggestions?


0 commentaires

6 Réponses :


1
votes

Oui, ça me dérangeait aussi. C'est ce que j'ai fait pour les rails 2.3.14 (ou plus bas): xxx pré>

puis dans votre contrôleur utilisez: p> xxx pré>

ou définissez-le Dans votre modèle si vous n'attendez pas de modifications au champ sérialisé une fois créé (mais update_attribute (: Serialized_field => "Mettez à jour moi" fonctionne toujours!) P>

class Model < ActiveRecord::Base
  serialize :serialized_field

  def no_serialize_update
    true
  end

end


4 commentaires

Cela semble assez prometteur. Merci! Maintenant que je sais quoi remplacer, je pourrais faire cela (en conjonction avec Super) au lieu d'utiliser la méthode enchaînant, sauf indication contraire de prendre cette approche. Faites-moi savoir si vous voyez des problèmes si j'utilise simplement le remplacement + super.


J'ai essayé ça aussi, mais remarqué que cela n'a pas fonctionné. Le problème est que update_with_dirty est déjà chargé (via la chaîne d'origine) avant d'avoir la chance de le remplacer et d'utiliser super.


@TABrez: AVERTISSEMENT: J'avais un insecte étrange dans mon application que les gemmes ACTS-AS-VERHEED et ALLICK_ID NE ont créé un enregistrement dans ma base de données lorsqu'un modèle a été mis à jour. Il semblait que le rappel avant_update a cessé de fonctionner dans mes modèles. Cela m'a pris beaucoup de temps avant que je puisse le lier au code ci-dessus dans ma demande. Je l'ai supprimé maintenant. Pas sûr (encore) pourquoi cela s'est passé.


@Joris je viens d'ajouter une réponse qui explique votre problème



2
votes

Voici une solution similaire pour les rails 3.1.3.

de: https://sites.google.com/site/wangsnotes/ruby/ror/z00---topics/fail-a-partial-update- avec-Serialized-Data P>

Mettez le code suivant dans Config / Initialiseurs / P>

ActiveRecord::Base.class_eval do
  class_attribute :no_serialize_update
  self.no_serialize_update = false
end

ActiveRecord::AttributeMethods::Dirty.class_eval do
  def update(*)
    if partial_updates?
      if self.no_serialize_update
        super(changed)
      else
        super(changed | (attributes.keys & self.class.serialized_attributes.keys))
      end
    else
      super
    end
  end
end


1 commentaires

Cela fonctionne (essayé sur ROR 3.2.18). Avez-vous ajouté: def no_serialize_update true Terminez le modèle contenant le Serialize Vous souhaitez que vous ne soyez pas mis à jour par défaut?



1
votes

J'ai couru dans ce problème aujourd'hui et j'ai fini par pirater mon propre sérieliseur avec un getter et un setter. D'abord, j'ai renommé le champ sur # {colonne} _raw code>, puis utilisé le code suivant dans le modèle (pour l'attribut multimédia code> dans mon cas).

require 'json'

...

def media=(media)
  self.media_raw = JSON.dump(media)
end

def media
  JSON.parse(media_raw) if media_raw.present?
end


1 commentaires

Solution géniale! Je serais intéressé d'entendre s'il y a des inconvénients, peut-être la performance? avoir à analyser le RAW à chaque fois?



1
votes

Le problème avec la réponse de Joris est qu'il accroche à la chaîne alias_mesthod_chain , désactivant toutes les chaînes effectuées après (comme update_with_callbacks qui explique les problèmes des déclencheurs non appelé). Je vais essayer de faire un diagramme pour faciliter la compréhension.

Vous pouvez commencer par une chaîne comme celle-ci xxx

remarque que update_without_foo points sur update_with_bar et et et et update_without_bar à update_with_baz

puisque vous ne pouvez pas modifier directement update_with_bar par les travaux internes de alias_method_chain vous Peut essayer de raccrocher dans la chaîne en ajoutant un nouveau lien (bar2) et appeler update_without_bar, donc: xxx

Malheureusement, cela vous permettra la chaîne suivante: xxx

SO update_with_foo est parti!

Donc, sachant que alias_method_chain ne vous laissera pas redéfinir _with méthodes Ma solution a été jusqu'à redéfinir update_without_dirty et faire la sélection d'attribut là-bas.


0 commentaires

0
votes

Il y a aussi des discussions dans https://github.com/rails/rails/issues/8328 .


0 commentaires

1
votes

Pas tout à fait une solution, mais une bonne solution de contournement dans de nombreux cas pour moi était simplement de déplacer la ou les colonnes sérialisées à un modèle associé - souvent, cela était en fait une bonne coupe sémantique de toute façon.


0 commentaires