Stop ActiveRecord saving a serialized column even if not changed

六月ゝ 毕业季﹏ 提交于 2019-11-28 04:00:20

问题


This is very similar to Rails partial updates problem with hashes , but the question has not really been answered IMHO.

The problem is this: I have a model with a serialized column:

class Import < AR::Base
  serialize :data

In my case, this data will, and should, not change after the first save/creation of the model. So I want to disable the feature of AR that always saves serialized columns (which is normally a good idea, as it can't detect those changes). I want to disable the saving because the data can be quite large, and the model will be updated frequently.

I've already tried monkeypatching into ActiceRecord::AttributeMethods::Dirty like this:

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

but this seems to have no effect. Anybody got a better idea ?

This is under Rails 3.0.12


回答1:


What I ended up doing, even though it's not really an answer to the original question, is the following:

class Import < AR::Base
  belongs_to :storage

class Storage < AR::Base
  serialize :data

...i.e. moving the data column into a model of its own, and associate that with the original model. Which is actually conceptually somewhat cleaner.




回答2:


Here is an ugly monkey patch solution:

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

You will have to remember to call cache_spam!, or your serialized attribute will never be saved.



来源:https://stackoverflow.com/questions/9981257/stop-activerecord-saving-a-serialized-column-even-if-not-changed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!