1

DataMapper を使用して、全体を変更しない限りObject、プロパティが更新されないことに気付きました。オブジェクトのフィールドを更新してから保存すると、変更が保持されません。

クラスにプロパティとして保存しているクラスのvalue属性を更新しています。UnitValueObjectProductQuantity

require 'data_mapper'

class ProductQuantity
  include DataMapper::Resource
  property :id, Serial
  property :quantity, Object, :required => true
end

# RSpec:

# Create a UnitValue with value 300, save as the Object property of this ProductQuantity
prod_quantity1 = ProductQuantity.create(:quantity => UnitValue.new(300, 'kg'))
expect(prod_quantity1.quantity.value).to eql(300) # true

# Replace the entire UnitValue object
prod_quantity1.quantity = UnitValue.new(400, 'kg')
expect(prod_quantity1.quantity.value).to eql(400)
prod_quantity1.save

# Check save worked when modifying the entire object
expect(ProductQuantity.get(prod_quantity1.id).quantity.value).to eql(400) # true

# Modify only a single field
prod_quantity1.quantity.value = 500
prod_quantity1.save

# Check save worked when modifying a single object - this FAILS
expect(ProductQuantity.get(prod_quantity1.id).quantity.value).to eql(500) # false
4

1 に答える 1

0

ドキュメントを調べてこの古いスレッドを見つけた後、解決策を見つけたと思います。インスタンスの persistence_state を変更することで、属性をダーティとしてマークできDataMapper::Resourceます。

DirtyState = DataMapper::Resource::PersistenceState::Dirty
quantity_property = ProductQuantity.properties[:quantity]

old_quantity = prod_quantity1.quantity
prod_quantity1.quantity.value = 500
dirty_state = DataMapper::Resource::PersistenceState::Dirty.new(prod_quantity1)
dirty_state.original_attributes[quantity_property] = old_quantity
prod_quantity1.persistence_state = dirty_state
expect(prod_quantity1.persistence_state.is_a? DirtyState).to eql(true)
expect(prod_quantity1.dirty?).to eql(true)
prod_quantity1.save
expect(prod_quantity1.dirty?).to eql(false)

基本的に、DataMapper::Resource::PersistenceState::Dirtyオブジェクトを作成し、ProductQuantity の「quantity」プロパティをキーとして使用して、値を の古いオブジェクトとして設定しますoriginal_attributes。空でないマップは、 に対して true を返しますprod_quantity1.dirty?

以下のモジュールにしました。<resource_instance>.make_dirty(*attributes)いくつかの属性名で呼び出すだけです。

require 'data_mapper'

module DataMapper
  module Resource

    # Make the give attributes dirty
    def make_dirty(*attributes)
      if attributes.empty?
        return
      end
      unless self.clean?
        self.save
      end
      dirty_state = DataMapper::Resource::PersistenceState::Dirty.new(self)
      attributes.each do |attribute|
        property = self.class.properties[attribute]
        # Any value will do here and return true for self.dirty?, but it expects the old version of this attribute.
        dirty_state.original_attributes[property] = nil
        self.persistence_state = dirty_state
      end
    end

  end
end

そして、私はそれを以下でテストしました:

describe DataMapper::Resource do

  before(:all) do
    DataMapper.auto_migrate!
    @prod1 = Product.create(:name => 'Snickers')
  end

  after(:all) do
    DataMapper.auto_migrate!
  end

  it 'should fail when an attribute is not dirty' do
    prod_quantity1 = ProductQuantity.create(:product => @prod1, :quantity => UnitValue.new(300, 'kg'))
    prod_quantity1.quantity.value = 400
    expect(prod_quantity1.dirty?).to eql(false)
    prod_quantity1.save
    prod_quantity1 = ProductQuantity.get(prod_quantity1.id)
    expect(prod_quantity1.quantity.value).to eql(300)
  end

  it 'should mark an attribute as dirty' do
    prod_quantity1 = ProductQuantity.create(:product => @prod1, :quantity => UnitValue.new(300, 'kg'))
    prod_quantity1.quantity.value = 400
    expect(prod_quantity1.dirty?).to eql(false)
    prod_quantity1.make_dirty(:quantity)
    expect(prod_quantity1.dirty?).to eql(true)
    prod_quantity1.save
    expect(prod_quantity1.quantity.value).to eql(400)
    expect(prod_quantity1.dirty?).to eql(false)
  end

end
于 2013-09-09T15:20:52.690 に答える