ruby-on-rails - has_many :through with class_name and foreign_key

标签 ruby-on-rails ruby-on-rails-4

我正在处理一个相当简单的 has_many through: 情况,我可以使 class_name/foreign_key 参数在一个方向上工作,但不能在另一个方向上工作。也许你能帮帮我。 (附注:我使用的是 Rails 4,如果这会产生差异):

英文:一个User通过ListingManager管理多个Listing,一个Listing由多个User通过ListingManager管理。列表管理器有一些数据字段,与这个问题无关,所以我在下面的代码中编辑了它们

这是有效的简单部分:

class User < ActiveRecord::Base
  has_many :listing_managers
  has_many :listings, through: :listing_managers
end

class Listing < ActiveRecord::Base
  has_many :listing_managers
  has_many :managers, through: :listing_managers, class_name: "User", foreign_key: "manager_id"
end

class ListingManager < ActiveRecord::Base
  belongs_to :listing
  belongs_to :manager, class_name:"User"

  attr_accessible :listing_id, :manager_id
end

正如您可以从上面的 ListingManager 表中猜到的那样:
create_table "listing_managers", force: true do |t|
  t.integer  "listing_id"
  t.integer  "manager_id"
end

所以这里唯一不简单的是ListingManager使用manager_id而不是 user_id
无论如何,上述工作。我可以调用user.listings获取与用户关联的列表,我可以调用 listing.managers获取与列表关联的经理。

但是(这是问题所在),我认为说 user.listings 并没有多大意义。因为用户也可以“拥有”而不是“管理”列表,所以我真正想要的是 user.managed_listings所以我调整了user.rb改变
has_many :listings, 通过: :listing_managers

has_many:managed_listings,通过::listing_managers,class_name:“Listing”,foreign_key:“listing_id”

这与 listing.rb 中的代码完全类似。上面,所以我认为这应该可以正常工作。相反,我对这个 barfs 的 rspec 测试是这样说的ActiveRecord::HasManyThroughSourceAssociationNotFoundError: Could not find the source association(s) :managed_listing or :managed_listings in model ListingManager. Try 'has_many :managed_listings, :through => :listing_managers, :source => <name>'. Is it one of :listing or :manager?
测试是:
it "manages many managed_listings"  do
  user = FactoryGirl.build(:user)
  l1 = FactoryGirl.build(:listing)
  l2 = FactoryGirl.build(:listing)     
  user.managed_listings << l1
  user.managed_listings << l2
  expect( @user.managed_listings.size ).to eq 2
end

现在,我确信我什么都不知道。是的,我想我可以做一个别名,但我很困扰 listing.rb 中使用的相同技术似乎在 user.rb 中不起作用.你能帮忙解释一下吗?

更新:
我更新了代码以反射(reflect)@gregates 的建议,但我仍然遇到了一个问题:我编写了一个失败的附加测试(并通过 Rails 控制台中的“手动”测试确认)。当一个人编写这样的测试时:
it "manages many managed_listings"  do
  l1 = FactoryGirl.create(:listing)
  @user = User.last
  ListingManager.destroy_all
  @before_count = ListingManager.count
  expect(  @before_count ).to eq 0
  lm = FactoryGirl.create(:listing_manager, manager_id: @user.id, listing_id: l1.id)


  expect( @user.managed_listings.count ).to eq 1
end

以上失败。 Rails 生成错误 PG::UndefinedColumn: ERROR: column listing_managers.user_id does not exist (它应该在寻找“listing_managers.manager_id”)。所以我认为关联的用户端仍然存在错误。在 user.rbhas_many :managed_listings, through: :listing_managers, source: :listing ,用户怎么知道使用manager_id去它的列表(S)?

最佳答案

这里的问题是

has_many :managers, through: :listing_managers
ActiveRecord 可以推断出连接模型上的关联名称 (:listing_managers),因为它与 has_many :through 具有相同的名称。您正在定义的关联。也就是说,listings 和 listing_mangers 都有很多管理器。
但在您的其他协会中并非如此。在那里,一个listing_manager has_many :listings , 但用户 has_many :managed_listings .因此 ActiveRecord 无法推断 ListingManager 上的关联名称它应该使用。
这就是 :source选项适用于(见 http://guides.rubyonrails.org/association_basics.html#has-many-association-reference)。所以正确的声明是:
has_many :managed_listings, through: :listing_managers, source: :listing
(附注:您实际上并不需要其他 :foreign_key 上的 :class_namehas_many :through 选项。您可以使用这些选项来定义直接关联,然后在 has_many :through 上只需要指向正确的:through 模型上的关联。)

关于ruby-on-rails - has_many :through with class_name and foreign_key,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18154736/

相关文章:

ruby-on-rails - Rails - 流量控制问题,有更好的方法吗?

ruby-on-rails - pundit rspec - 未初始化的常量 UserPolicy,为什么?

ruby-on-rails - Rails 生产 : Premature end of script headers

ruby-on-rails - 在 Ruby、rails3 中创建数组

ruby-on-rails - 如何在 Rails 中干燥模型?

ruby-on-rails - rails : PayPal Express Checkout Integration in Localhost

ruby-on-rails-4 - 将 simple_forms simple_field_for 与 Carrierwave 的多部分文件 uploader 一起使用

ruby-on-rails - 无法启动 Rails Server,捆绑安装不起作用

ruby-on-rails - rails : OR where condition on association

ruby-on-rails-4 - 将 Rails 升级到 4.2.3+ 后,FactoryGirl 导致 NoMethodError