【问题标题】:How can I get an ActiveRecord::Association to initialize a parent's auto-loaded children's parent references to point at the actual parent object?如何获得 ActiveRecord::Association 来初始化父对象的自动加载的子对象的父引用以指向实际的父对象?
【发布时间】:2012-08-30 03:47:49
【问题描述】:

这是在 Ruby 1.9.3p194 和 Rails 3.2.8 中

app/models/owner.rb:

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

app/models/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 中也能正常工作。

【问题讨论】:

  • 你不能,ActiveRecord 不适合这个。你可能想看看 DataMapper。

标签: ruby-on-rails ruby activerecord associations arel


【解决方案1】:

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

app/models/owner.rb:

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

app/models/pet.rb:

class Pet < ActiveRecord::Base
  attr_accessible :name, :owner
  belongs_to :owner, :inverse_of => :pets
end

【讨论】:

    【解决方案2】:

    克里斯,

    你缺少的是这个;

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

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

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

    【讨论】:

      【解决方案3】:

      想通了。这适用于 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_ids 和 shaggy.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
      

      app/models/owner.rb:

      class Owner < ActiveRecord::Base
        attr_accessible :name
        has_many :pets, :extend => RememberParentExtension.new(:owner)
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-04
        相关资源
        最近更新 更多