0

这是 Ruby 1.9.3p194 和 Rails 3.2.8

应用程序/模型/所有者.rb:

class Owner < ActiveRecord::Base
  attr_accessible :name
  has_many :pets
end

应用程序/模型/pet.rb:

class Pet < ActiveRecord::Base
  attr_accessible :name, :owner
  belongs_to :owner
end

db/migrate/20120829184126_create_owners_and_pets.rb:

class CreateOwners < ActiveRecord::Migration
  def change
    create_table :owners do |t|
      t.string :name
      t.timestamps
    end
    create_table :pets do |t|
      t.string :name
      t.integer :owner_id
      t.timestamps
    end
  end
end

好吧,现在看看会发生什么……

# rake db:migrate
# rails console
irb> shaggy = Owner.create(:name => 'Shaggy')
irb> shaggy.pets.build(:name => 'Scooby Doo')
irb> shaggy.pets.build(:name => 'Scrappy Doo')
irb> shaggy.object_id
  => 70262210740820
irb> shaggy.pets.map{|p| p.owner.object_id}
  => [70262210740820, 70262210740820]
irb> shaggy.name = 'Shaggie'
irb> shaggy.name
  => "Shaggie"
irb> shaggy.pets.map{|p| p.owner.name}
  => ["Shaggie", "Shaggie"]
irb> shaggy.save
irb> shaggy.reload
irb> shaggy.object_id
  => 70262210740820
irb> shaggy.pets.map{|p| p.owner.object_id}
  => [70262211070840, 70262211079640]
irb> shaggy.name = "Fred"
irb> shaggy.name
  => "Fred"
irb> shaggy.pets.map{|p| p.ower.name}
  => ["Shaggie", "Shaggie"]

我的问题:我怎样才能让 rails 初始化 shaggy.pets 的元素以使其所有者设置为 shaggy (确切的对象),不仅是在首次构建/创建宠物对象时,而且即使它们是从自动加载的通过关联的数据库?

加分项:让它在 Rails 2.3.5 中也能正常工作。

4

3 回答 3

1

如果你不关心 2.3.5 的支持,下面的就简单多了:

应用程序/模型/所有者.rb:

class Owner < ActiveRecord::Base
  attr_accessible :name
  has_many :pets, :inverse_of => :owner
end

应用程序/模型/pet.rb:

class Pet < ActiveRecord::Base
  attr_accessible :name, :owner
  belongs_to :owner, :inverse_of => :pets
end
于 2013-01-16T04:27:05.120 回答
0

克里斯,

你缺少的是这个;

  • 当您查询数据库时,您会在那个确切时刻拍摄数据的快照。
  • 您的关联不指向对象引用,它们是从数据库中查询的对象的浅表副本。
  • 为了使您的代码正常工作,您需要将对象保存回数据库,以便宠物适当地获取更新。

我还会展示更多代码,因为我可以清楚地看到你在做的事情上采取了错误的方向。

您展示的是一个桌面应用程序模式示例,它使用了为 Web 应用程序设计的模式。

于 2012-08-30T05:01:58.010 回答
0

弄清楚了。这适用于 Rails 3.2.8 和 Rails 2.3.5:

class Owner < ActiveRecord::Base
  attr_accessible :name
  has_many :pets do
    def load_target
      super.map do |pet|
        pet.owner = (proxy_association.owner rescue proxy_owner)
        pet
      end
    end
  end
end

请注意,在 Rails 2.3.5 中,object_idsshaggy.pets.map{|p| p.owner}仍然不同,因为它们是不同的 ProxyAssociation 对象,但它们至少指向同一个底层对象。

如果您经常这样做,您可能想要概括...

lib/remember_parent_extension.rb:

class RememberParentExtension < Module
  def initialize(parent_name)
    parent_setter = "#{parent_name}="
    super() do
      define_method(:load_target) do
        super.map do |child|
          parent_proxy = (proxy_association.owner rescue proxy_owner)
          child.send(parent_setter, parent_proxy)
          child
        end
      end
    end
  end
end

应用程序/模型/所有者.rb:

class Owner < ActiveRecord::Base
  attr_accessible :name
  has_many :pets, :extend => RememberParentExtension.new(:owner)
end
于 2012-08-30T15:15:58.530 回答