Ruby Sequel json 列上的脏状态无法使用 Postgresql

Ruby Sequel dirty status on json column not working using Postgresql

使用 sequel 4.29.0。

我打算使用 before_save sequel 钩子来触发一个动作,在这种情况下,我需要确定特定的列是否发生了变化,在以前的实现中我使用了 @changed_columns sequel 实例变量以获取更改的列的列表以及类似的内容:

class MyModel < Sequel::Model
  def before_save
    special_method if @changed_columns.include? :properties

    super
  end

  def special_method
    ...
  end
end

这次我使用的是 Postgresql jsonb 类型的列(顺便说一句,非常方便)。每次我使用修改该列时,@changed_columns 永远不会保留该列,我知道我可以将一列指定为 "dirty",但这意味着我必须更改此列已更改的所有位置,有时不会就这么简单。

这不起作用的示例:

irb(main):001:0> MyModel.columns
=> [:id, :foo, :properties]     # :foo is a string, :properties is jsonb

irb(main):002:0> my_model = MyModel.last
=> #<MyModel @values={:id=>37, :foo=>"bar", :properties=>{"foo"=>true}}>

irb(main):003:0> my_model.properties['foo'] = false
=> false

irb(main):004:0> my_model
=> #<MyModel @values={:id=>37, :foo=>"bar", :properties=>{"foo"=>false}}>

irb(main):005:0> my_model.modified?
=> false                        # this should be true since properties changed a value inside the hash

irb(main):006:0> my_model.foo = 'foo'
=> "foo"

irb(main):007:0> my_model
=> #<MyModel @values={:id=>37, :foo=>"foo", :properties=>{"foo"=>false}}>

irb(main):008:0> my_model.modified?
=> true

irb(main):009:0> my_model.changed_columns
=> [:foo]                       # should include the :properties column

这是 Sequel 的预期默认行为。如果你想检测列值的突变,你需要使用 modification_detection 插件:

DB.extension :pg_json
DB.create_table!(:bs){primary_key :id; jsonb :properties}
class B < Sequel::Model; end
B.plugin :modification_detection
B.create(:properties=>{'a'=>1})
b = B.first
b.properties['a'] = 2
b.modified?
# => true