2012-04-02 9 views
6

Dies ist sehr ähnlich zu Rails partial updates problem with hashes, aber die Frage wurde nicht wirklich beantwortet IMHO.Stop ActiveRecord Speichern einer serialisierten Spalte auch wenn nicht geändert

Das Problem ist folgendes: ich ein Modell mit einer serialisierten Spalte:

class Import < AR::Base 
    serialize :data 

In meinem Fall werden diese Daten und sollte nicht geändert werden, nachdem die erste des Modells speichern/Schöpfung. Also möchte ich die Funktion von AR deaktivieren, die immer serialisierte Spalten speichert (was normalerweise eine gute Idee ist, da sie diese Änderungen nicht erkennen kann). Ich möchte das Speichern deaktivieren, da die Daten sehr groß sein können und das Modell häufig aktualisiert wird.

ich bereits habe versucht monkeypatching in ActiceRecord :: AttributeMethods :: Schmutzige wie folgt aus:

class Import 
    def update(*) 
    if partial_updates? 
     super(changed | (attributes.keys & (self.class.serialized_attributes.keys - ["data"]))) 
    else 
    super 
    end 
end 

aber dies scheint keine Wirkung zu haben. Hat jemand eine bessere Idee?

Dies ist unter Rails 3.0.12

Antwort

6

Was ich tun am Ende, auch wenn es auf die ursprüngliche Frage nicht wirklich eine Antwort ist, ist die folgende:

class Import < AR::Base 
    belongs_to :storage 

class Storage < AR::Base 
    serialize :data 

... d.h. Verschieben der Datenspalte in ein eigenes Modell und Verknüpfen dieses mit dem ursprünglichen Modell. Was konzeptionell etwas sauberer ist.

+0

Das macht wirklich viel Sinn, danke für den Einblick. Ich denke, ich werde den gleichen Weg gehen und eine polymorphe Assoziation zwischen dem _Storage_ Modell und anderen verwenden, die nur serialisierte Spalten haben –

3

Hier ist eine hässliche Affe Patch Lösung:

module ActiveRecord 
    module AttributeMethods 
    module Dirty 
     def update(*) 
     if partial_updates? 
      # Serialized attributes should always be written in case they've been 
      # changed in place. Unless it is 'spam', which is expensive to calculate. 
      super(changed | (attributes.keys & self.class.serialized_attributes.keys - ['spam'])) 
     else 
      super 
     end 
     end 
     private :update 
    end 
    end 
end 
class Foo < ActiveRecord::Base 
    serialize :bar 
    serialize :spam 


    def calculate_spam 
    # really expensive code 
    end 

    def cache_spam! 
    calculated_spam = calculate_spam 
    @changed_attributes['spam'] = [spam, calculated_spam] 
    self.update_attribute(:spam, calculated_spam) 
    end 
end 

Sie müssen sie daran zu erinnern cache_spam zu rufen !, oder Ihr serialisierten Attribut wird nie gespeichert werden.