Search code examples
ruby-on-rails-4simple-formnested-attributeshas-many-through

Rails - use collection_select in a simple_form for a has_many_through association


I need help with a create form for a has_many_through association which also specifies a class name:

class Sponsor < ActiveRecord::Base
  has_many :member_contacts
  has_many :contacts, through: member_contacts, class_name: :member

  accepts_nested_attributes_for :address, :contacts
end

class Contact < ActiveRecord::Base
  has_many :member_contacts
  has_many :sponsors, through: member_contacts
end

class MemberContact  < ActiveRecord::Base
  belongs_to :contact
  belongs_to :sponsor
end

sponsors_controller.rb

def create
  @sponsor = Sponsor.create(sponsor_params)
  @sponsor.contacts.build
end

def sponsor_params
  params.require(:sponsor).permit(:name,:website,:email, 
  :contact_first_name, :contact_surname, contacts_attributes: [], address_attributes: [:flat, :street, :postal_code, :city])
end

sponsor/_form.html.haml

= simple_form_for @sponsor do |f|
  = f.association :contacts, collection: Member.all, label_method: :full_name

This is failing with the error 'unpermitted params, contact_ids', because

"contact_ids"=>["", "4", "5", "6"]

is being passed in the params hash. In the form I'd like a drop down list of all the members and the ability to select multiple members which will be saved against the sponsor as contacts.

How do I set up the contacts_attributes in sponsor_params in the controller and the collection_select simple_form helper in the view?


Solution

  • To get the form working, I added a foreign key to the sponsor class

    has_many :contacts, through: member_contacts, class_name: 'Member', foreign_key 'member_id'
    

    changed the strong params in the controller

    def sponsor_params
      params.require(:sponsor).permit(:name,:website,:email, contact_first_name, :contact_surname, contact_ids: [], address_attributes: [:flat, :street, :postal_code, :city])
    end
    

    and removed the association in the view, using collection_select

    = f.collection_select :contact_ids, Member.all, :id, :full_name, 
          { selected: @sponsor.contacts.map(&:id) }, { multiple: true }