Inserting rows into linking table

David Lelong пишет:

Hi,

I have two objects:

Contacts
Lists

I want to be able to add multiple contacts to multiple lists.

I've created a linking table and a form that allows me to select the contacts using checkboxes, but I'm having some problems with the controller and model.

I receive the following error message when I submit the form:

Mysql::Error: Cannot add or update a child row: a foreign key constraint fails: INSERT INTO contact_lists (`contact_id`, `list_id`) VALUES(1, 2)

However, the form variables returned from the form are:

Parameters: {"commit"=>"Add Contacts to List", "contact_list"=>{"contact_id"=>["4", "5"], "list_id"=>"2"}}

I'm not sure if the issue is with the way my controller is setup or the model.

The controller action is:

  def link_contacts
    @contact_list = Contact_List.new(params[:contact_list])
    if @contact_list.save
      flash[:notice] = 'Contacts were successfully added to the list.'
      redirect_to :action => 'list'
    else
      flash[:notice] = 'Error with adding contacts to the list.'
    end
  end

Any advice?
  

You are trying to pass an array as an attribute value ("contact_id"). This won't work. You have to iterate through all items in params[:contact_list][:contact_id]:
@contacts = params[:contact_list][:contact_id].collect { |contact_id| Contact_List.new(:list_id => params[:list_id], :contact_id => contact_id) }

But I'm in doubt you have business model designed right.

@contacts = params[:contact_list][:contact_id].collect { |contact_id|
Contact_List.new(:list_id => params[:list_id], :contact_id =>
contact_id) }

Ahh.. don't ever copy/paste the code. Read it, get the idea and then type it
YOURSELF. Here is the corrected one:

@contacts = params[:contact_list][:contact_id].collect { |contact_id|
Contact_List.new(:list_id => params[:contact_list][:list_id], :contact_id =>
contact_id) }

By the way, you should create an abstraction for link between Contact and List
and name the corresponding class according to that abstraction. Contact_List
looks not very nice for me.

David Lelong wrote:

I'm still receiving an error message when I don't select a contact_id:

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occured while evaluating nil.collect

Any advice?

This is because you use checkboxes in the HTML and they do not produce
any post parameter if they aren't selected. My suggestion is to add
"rescue" clause for that case:

@contact_lists = .......... rescue []

The middle part is unchanged, only add "rescue []" to catch any errors
and return empty array then. Alternatively, you can wrap all construct
in an IF block:

if params[:contact_list] && params[:contact_list][:contact_id]
  @contact_lists = ....................
end

Hello David,

Ugh, it had to do with:

validates_uniqueness_of :contact_id, :list_id

in my controller

Any advice on how I can get validate for uniqueness on the combination
of contact_id and list_id, not each one individually?

You were not so far :slight_smile:
Use :scope.

validates_uniqueness_of :contact_id, :scope => :list_id

Regards,

     -- Jean-François.