有没有一种方法可以防止rails中的序列化属性即使没有更改也无法更新



这可能是所有新用户迟早会发现的关于Rails的事情之一。我刚刚意识到rails正在使用serialize关键字更新所有字段,而不检查内部是否真的发生了变化。在某种程度上,对于通用框架来说,这样做是明智的。

但是有没有办法推翻这种行为?如果我可以跟踪序列化字段中的值是否发生了更改,那么有没有办法防止它在update语句中被推送?我尝试使用"update_attributes"并将散列限制在感兴趣的字段,但rails仍然会更新所有序列化的字段。

建议?

这里有一个类似的Rails 3.1.3解决方案。

发件人:https://sites.google.com/site/wangsnotes/ruby/ror/z00---topics/fail-to-partial-update-with-serialized-data

将以下代码放入config/ininitializers/

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

是的,这也困扰着我。这就是我为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

我今天遇到了这个问题,最后用getter和setter一起破解了我自己的序列化程序。首先,我将字段重命名为#{column}_raw,然后在模型中使用以下代码(在本例中用于media属性)。

require 'json'
...
def media=(media)
  self.media_raw = JSON.dump(media)
end
def media
  JSON.parse(media_raw) if media_raw.present?
end

现在,部分更新对我来说非常有效,并且只有当数据实际更改时,字段才会更新。

Joris的答案的问题是它挂接到alias_method_chain链,禁用之后完成的所有链(如update_with_callbacks,它解决了触发器未被调用的问题)。我会试着做一张图表,使它更容易理解。

你可以从这样的链开始

update -> update_with_foo -> update_with_bar -> update_with_baz

注意,update_without_foo指向update_with_barupdate_without_bar指向update_with_baz

由于您无法根据alias_method_chain的内部工作直接修改update_with_bar,因此您可能会尝试通过添加新链接(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,并在那里进行属性选择。

这不是一个很好的解决方案,但在许多情况下,对我来说,一个好的解决方法只是将序列化的列移动到一个关联的模型中——通常情况下,这在语义上是非常合适的。

https://github.com/rails/rails/issues/8328.

相关内容

  • 没有找到相关文章

最新更新