Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

has_and_belongs_to_many autosaves duplicate records #3639

Closed
al2o3cr opened this Issue Nov 15, 2011 · 4 comments

Comments

Projects
None yet
4 participants
Contributor

al2o3cr commented Nov 15, 2011

Under certain circumstances, the autosave system can wind up creating duplicate HABTM join records. To reproduce:

class Project < ActiveRecord::Base
  has_and_belongs_to_many :users
end

class User < ActiveRecord::Base
  attr_accessor :first_project_id
  after_create :set_first_project
  has_and_belongs_to_many :projects

  protected

  def set_first_project
    self.projects << Project.find(first_project_id)
  end
end

@project = Project.new(:name => 'foo')
@user = User.new(email => 'foo@example.com', :first_project_id => @project.id)
# result: two records created in projects_users

Note: this is, ultimately, a code-ordering issue. Moving the after_create to after the HABTM declaration avoids the issue.

This is caused by the code in autosave_association.rb calling insert_record for every record in the HABTM, even the ones added in the after_create callback (which have already been inserted).

Contributor

qoobaa commented Nov 26, 2011

It seems the behaviour is intentional. There's even test for that in https://github.com/rails/rails/blob/master/activerecord/test/models/eye.rb

has_and_belongs_to_many sets up two callbacks: after_create and after_update. Those callbacks are responsible for saving associated models. You probably want your callback to be run after the autosave one, that's why it should be placed after habtm call.

Contributor

qoobaa commented Nov 26, 2011

Maybe we should ask @fxn about that. /cc @fxn

@drogus drogus closed this Nov 28, 2011

Member

drogus commented Nov 28, 2011

I pushed qoobaa's documentation updaate, it should be clear what's the reason now.

So, what happened with this, because I just killed an hour trying to figure out what was going on, only to find changing the order made it go away.

Should callbacks always go after relations? Is that a Rails-ism I just didn't know about?
Looks like it's caught at least one other person out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment