Strange has_many: problem with adding objects to a collection

advertisements

Bounty of $25 for the first working solution.

I'm seeing a really weird has_many :through problem with ActiveRecord.

With these classes:

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

I get this behaviour:

>> 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

Adding an object to the :through collection appears to add two items to the root association, both missing the ID of the object added.

Does anyone have any ideas why this might be happening?

Edit: Even this doesn't work:

>> 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>]


Ok, so after a long and rather frustrating search for the answer to this, I finally tracked down the issue and it's a damned embarrassing one.

I was using the following dynamic attr_accesssible code in an initializer:

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

Which I had conveniently forgotten about and which caused number_id to be inaccessible (thanks to the empty attr_accessible call).