2

如果第一个属性由值对象表示,为什么我不能在保存当前对象的关联对象中保存更改?

例如,我有一个简单的电子商务应用程序。它使用客户端模型来操作客户端

客户模型


# db/migrate/<...>_create_clients.rb

class CreateClients < ActiveRecord::Migration
  def self.up
    create_table :clients do |t|
      t.string :name
    end
  end

  def self.down
    drop_table :clients
  end
end


# app/models/client.rb

Client < ActiveRecord::Base
  has_one :balance
end

以及用于持有余额的关联余额模型。

平衡模型


# db/migrate/<...>_create_balances.rb

class CreateBalances < ActiveRecord::Migration
  def self.up
    create_table :balances do |t|
      t.integer    :amount
      t.string     :currency
      t.references :client
    end
  end

  def self.down
    drop_table :balances
  end
end


# app/models/balance.rb

class Balance < ActiveRecord::Base
  belongs_to :client

  composed_of :money,
    :mapping     =>
      [%w{amount cents}, %w{currency currency_as_string}],
    :constructor =>
      ->(amount, currency) { Money.new(amount || 0, currency || 'RUB') }
end

Balance模型使用来自名为Money的外部库的Money对象。该对象表示模型的属性数量货币,为模型添加了用于操作这些属性的有用方法。

宝石文件


# Gemfile

gem 'money'

我在seed.rb中有一些种子数据。

种子


# db/seeds.rb

elena = Client.create(:name => 'Elena')
elena.build_balance.money = Money.new(0, 'RUB')
elena.save

当我尝试更改客户端的余额时,尽管当前对象的save方法返回true ,但它并没有改变。


>> elena = Client.find_by_name('Elena')
=> #<Client id: 1, name: "Elena">

>> elena.balance
=> #<Balance id: 1, amount: 0, currency: "RUB", client_id: 1>

>> elena.balance.money
=> 0.00

>> elena.balance.money += Money.new(50000, 'RUB')
=> 500.00

>> elena.save
=> true

# log/development.log
# no changes

但是,我可以使用以下两种方式保存更改。

1.


>> elena = Client.find_by_name('Elena')
=> #<Client id: 1, name: "Elena">

>> balance = Balance.find(elena.id)
=> #<Balance id:1 , amount: 0, currency: "RUB", client_id: 1>

>> balance.money += Money.new(50000, 'RUB')
=> 500.00

>> balance.save
=> true

# log/development.log
# UPDATE "balances" SET "amount" = 50000 WHERE ("balances"."id" = 1)

2.


>> elena = Client.find_by_name('Elena')
=> #<Client id:1, name:"Elena">

>> elena.balance.money += Money.new(50000, 'RUB')
=> 500.00

>> elena.balance.save
=> true

# log/development.log
# UPDATE "balances" SET "amount" = 50000 WHERE ("balances"."id" = 1)

尽管我可以使用上述方式保存余额更改,但我想知道为什么我不能使用“传统” <current_model> .save 方法来保存。

谢谢。

Debian GNU/Linux 5.0.6;

红宝石 1.9.2;

Ruby on Rails 3.0.1;

金钱 3.1.5。

4

1 回答 1

1

它是通过这样做来完成的:

# app/models/client.rb

Client < ActiveRecord::Base
  has_one :balance, :autosave => true
end

之前关联的问题是,当您调用 elena.save 时,它​​只是查看 Client 对象是否已更改。如果您在第一个示例中执行了这样的检查:

>> elena.changed?
=> false
>> elena.balance.changed?
=> true

如果您不通知 ActiveRecord 检查关联的模型,它将在保存父模型时变得懒惰并忽略更改。

于 2010-11-07T12:43:31.430 回答