This project is archived and is in readonly mode.

#6552 ✓resolved
Pawel

Rails 3 has_many through forces developer to make *_id attributes unprotected

Reported by Pawel | March 9th, 2011 @ 09:15 PM

In the classic Group <-> Membership <-> User scenario:

class Group
  has_many :memberships
  has_many :users, :through => :memberships
end

class Membership
  belongs_to :user
  belongs_to :group
end

class User
  has_many :memberships
end

If Membership has:

attr_protected :user_id, :group_id

Then executing:

group = Group.create!
user = User.create!

group.users << user
group.users.include? user # => true
group.users.reload.include? user # => false

Causes membership creation to fail.

From my research, it appears this is due to new way of creating "through" models in Rails 3.
Through models are now created using mass-assignment.

The problem lies in ActiveRecord::Associations::HasManyThroughAssociation#insert_record method defined in lib/active_record/associations/has_many_through_association.rb file.

Here is a quick monkey patch which resolves the issue (put it in config/initializers/fix_has_many.rb):

class ActiveRecord::Associations::HasManyThroughAssociation
  protected

  def insert_record(record, force = true, validate = true)
    if record.new_record?
      if force
        record.save!
      else
        return false unless record.save(:validate => validate)
      end
    end

    through_association = @owner.send(@reflection.through_reflection.name)

    through_association.create! do |r|
      construct_join_attributes(record).each { |k, v| r.send "#{k}=", v }
    end
  end
end

Comments and changes to this ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages