Есть ли способ предотвратить обновление сериализованных атрибутов в rails, даже если нет изменений?
Это, вероятно, одна из вещей, которые все новые пользователи узнают о Rails рано или поздно. Я только что понял, что rails обновляет все поля с помощью ключевого слова serialize, не проверяя, действительно ли что-то изменилось внутри. Таким образом, это разумная вещь для общей структуры.
но есть ли способ переопределить это поведение? Если я могу отслеживать, изменились ли значения в сериализованных полях или нет, есть ли способ предотвратить это толкнул инструкцию update? Я попытался использовать "update_attributes" и ограничить хэш интересующими полями, но rails по-прежнему обновляет все сериализованные поля.
предложения?
6 ответов
Да, это меня тоже беспокоило. Это то, что я сделал для Rails 2.3.14 (или ниже):
# config/initializers/nopupdateserialize.rb
module ActiveRecord
  class Base
    class_attribute :no_serialize_update
    self.no_serialize_update = false
  end
end
module ActiveRecord2
  module Dirty
    def self.included(receiver)
      receiver.alias_method_chain :update, :dirty2
    end
    private 
    def update_with_dirty2
      if partial_updates?
        if self.no_serialize_update
          update_without_dirty(changed)
        else
          update_without_dirty(changed | (attributes.keys & self.class.serialized_attributes.keys))
        end
      else
        update_without_dirty
      end
    end
  end
end
ActiveRecord::Base.send :include, ActiveRecord2::Dirty
тогда в вашем контроллере используйте:
model_item.no_serialize_update = true
model_item.update_attributes(params[:model_item])
model_item.increment!(:hits)
model_item.update_attribute(:nonserializedfield => "update me")
etc.
или определите его в своей модели, если вы не ожидаете каких-либо изменений в сериализованном поле после его создания (но update_attribute(:serialized_field => "update me" все еще работает!)
class Model < ActiveRecord::Base
  serialize :serialized_field
  def no_serialize_update
    true
  end
end
вот аналогичное решение для Rails 3.1.3.
поместите следующий код в config / initializers/
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
я столкнулся с этой проблемой сегодня и в конечном итоге взломал свой собственный сериализатор вместе с геттером и сеттером. Сначала я переименовал поле в #{column}_raw а затем использовал следующий код в модели (для  в моем случае).
require 'json'
...
def media=(media)
  self.media_raw = JSON.dump(media)
end
def media
  JSON.parse(media_raw) if media_raw.present?
end
Теперь частичные обновления отлично работают для меня, и поле обновляется только тогда, когда данные фактически изменены.
проблема с ответом Джориса в том, что он цепляется за alias_method_chain цепь, отключив все цепи, сделанные после (например,update_with_callbacks что объясняет проблемы триггеров, которые не вызываются). Я постараюсь сделать диаграмму, чтобы было легче понять. 
вы можете начать с цепи, как это
update -> update_with_foo -> update_with_bar -> update_with_baz
обратите внимание, что update_without_foo указывает на update_with_bar и update_without_bar to update_with_baz
так как вы не можете напрямую изменить update_with_bar в внутренние работы alias_method_chain вы можете попытаться подключиться к цепочке, добавив новую ссылку (bar2) и вызвав update_without_bar, так что:
alias_method_chain :update, :bar2
к сожалению, это даст вам следующие услуги:
update -> update_with_bar2 -> update_with_baz
так update_with_foo ушел!
Итак, зная, что alias_method_chain не позволит вам переопределить _with способы мое решение до сих пор было переопределить update_without_dirty и сделайте выбор атрибута там.
Не совсем решение, но хорошим обходным путем во многих случаях для меня было просто переместить сериализованный столбец(ы) в связанную модель - часто это действительно было хорошо подходит семантически в любом случае.
