奇怪的has_many:通过向集合添加对象的问题

时间:2010-11-14 18:08:46

标签: ruby-on-rails activerecord associations

第一个工作解决方案的25美元赏金。

我看到一个非常奇怪的has_many:通过ActiveRecord的问题。

使用这些课程:

create_table :numbers do |t|
  t.string :phone_number
end
create_table :call_lists do |t|
  t.string :type
  t.string :name
  t.integer :user_id
  t.integer :county_id
  t.integer :state_id
end
create_table :call_list_memberships do |t|
  t.integer :call_list_id
  t.integer :number_id
end

class CallList < ActiveRecord::Base
  attr_accessible :name
  has_many :call_list_memberships, :autosave => true
  has_many :numbers, :through => :call_list_memberships, :autosave => true
  belongs_to :user
end

class PoliticalDistrict < CallList
end

class CallListMembership < ActiveRecord::Base
  belongs_to :call_list
  belongs_to :number
end

class Number < ActiveRecord::Base
  attr_accessible :phone_number
  has_many :call_list_memberships
  has_many :call_lists, :through => :call_list_memberships
end

我得到这种行为:

>> p1 = PoliticalDistrict.first
=> #<PoliticalDistrict id: 2, type: "PoliticalDistrict", name: "Random political district", user_id: nil, county_id: nil, state_id: nil>
>> p1.numbers
=> []
>> p1.call_list_memberships
=> []
>> n1 = Number.first
=> #<Number id: 1, phone_number: "07921088939">
>> p1.numbers << n1
=> [#<Number id: 1, phone_number: "07921088939">]
>> p1.numbers
=> [#<Number id: 1, phone_number: "07921088939">]
>> p1.call_list_memberships
=> [#<CallListMembership id: 6, call_list_id: 2, number_id: nil>, #<CallListMembership id: 6, call_list_id: 2, number_id: nil>]
>> p1.save
=> true

将对象添加到:through集合似乎会向根关联添加两个项目,这两个项目都缺少添加的对象的ID。

有没有人有任何想法可能会发生这种情况?

编辑:即使这不起作用:

>> pd2.call_list_memberships.create :number => Number.first
=> #<CallListMembership call_list_id: 2, number_id: nil>
>> Number.first
=> #<Number id: 1, phone_number: "07921088939">
>> pd2.call_list_memberships
=> [#<CallListMembership call_list_id: 2, number_id: nil>]

2 个答案:

答案 0 :(得分:2)

好的,经过长时间而且相当令人沮丧的寻找答案之后,我终于找到了问题并且这是一个令人尴尬的尴尬。

我在初始化程序中使用了以下动态attr_accesssible代码:

class ActiveRecord::Base
  attr_accessible
  attr_accessor :accessible

  private

  def mass_assignment_authorizer
    if accessible == :all
      self.class.protected_attributes
    else
      super + (accessible || [])
    end
  end
end

我曾经方便地忘记了这个问题,导致number_id无法访问(感谢空的attr_accessible调用)。

答案 1 :(得分:0)

这确实是一种奇怪的行为。我不确定它是否仅与IRB或ActiveRecord本身有关。您会注意到正确地将关联保存到数据库,但IRB调用关联计数的结果是错误的。使用您的示例:

>> p1.call_list_memberships
=> [#<CallListMembership id: 6, call_list_id: 2, number_id: nil>, #<CallListMembership id: 6, call_list_id: 2, number_id: nil>]
>> p1.save
>> p1.call_list_memberships.length
=> 2 # Huh?
>> p1.call_list_memberships.size
=> 2 # Wtf?
>> p1.call_list_memberships.count
=> 1 # That's more like it
>> p1.reload # refresh the data
>> p1.call_list_memberships.length
=> 1 # now the associations are correct
>> p1.call_list_memberships.size
=> 1

更奇怪的是它重复了关联中的连接表行 - 检查两个CallListMemberships的对象ID,你会发现它们是相同的。

修改

使用连接表创建关联似乎可以避免此问题:

>> p1=PoliticalDistrict.create(:name=>"Sample")
=> #<PoliticalDistrict id: 1, type: "PoliticalDistrict", name: "Sample", user_id: nil, county_id: nil, state_id: nil, created_at: "2010-11-14 21:33:09", updated_at: "2010-11-14 21:33:09"> 
>> n1=Number.create(:phone_number=>"123")
=> #<Number id: 1, phone_number: "123", created_at: "2010-11-14 21:33:22", updated_at: "2010-11-14 21:33:22"> 
>> p1.call_list_memberships.create(:number=>n1)
=> #<CallListMembership id: 1, call_list_id: 1, number_id: 1, created_at: "2010-11-14 21:33:39", updated_at: "2010-11-14 21:33:39"> 
>> p1.call_list_memberships
=> [#<CallListMembership id: 1, call_list_id: 1, number_id: 1, created_at: "2010-11-14 21:33:39", updated_at: "2010-11-14 21:33:39">] 
>> p1.call_list_memberships.length
=> 1