So I have a similar situation going on as one of the users that posted here Rails 4 - checkboxes for has_and_belongs_to_many association, where this would be a perfect example:
#app/models/campaign.rb
class Campaign < ActiveRecord::Base
has_and_belongs_to_many :options
end
and then
#app/models/option.rb
class Option < ActiveRecord::Base
has_and_belongs_to_many :campaigns
end
Here's the way my join table migration look:
class CreateJoinTableCampaignsOptions < ActiveRecord::Migration[5.1]
def change
create_join_table :campaigns, :options do |t|
t.index [:campaign_id, :option_id], :unique => true, name: "CampaignO"
t.index [:option_id, :campaign_id], :unique => true, name: "OptionC"
end
end
end
Now I'm not sure if the "name" mentioned in the migration file has any play in the way I construct the view or anything, but this is just an example. In my real scenario, I am actually using much longer names than Campaign
and Option
, so the name field is absolutely required in the migration file.
With all of this being said, I want my Campaign form to show the option associated with it. If it's changed, I want the controller to change its association in the join table. Is this possible?
Here's my view for Campaign.
#app/views/campaigns/index.html.erb
<%= form_with(model: @campaign, local: true) do |form| %>
<%= form.collection_select :option_ids, Option.order("name ASC").all, "id", :name, prompt: "Select an option", class: "form-control" %>
<% end %>
Now when I submit this form, it looks like this in rails:
=> <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"3Dxl5mvuS82BzjM20CYgNgIMay4mNtOv3FY3E79onO/w7yN5wOfwsf20SzEh3VoRN+sLgAo22dhfxuI2zR6O+Q==", "campaign"=><ActionController::Parameters {"name"=>"HEllo World", "option_ids"=>"3"} permitted: false>, "controller"=>"campaign", "action"=>"create"} permitted: false>
The problem is that there is no association being created between Option
and Campaign
.
Trying to figure out what I'm missing here. I know it's something obvious but I can't figure it out. The only thing I can think of is creating another action in the controller and using that to create an association.
** Edit **
Here is the controller, which, again, is just default:
def create
@campaign = Campaign.new(campaign_params)
respond_to do |format|
if @campaign.save
format.html { redirect_back fallback_location: campaigns_path, notice: 'Campaign was successfully created.' }
format.json { render :show, status: :created, location: @campaign }
else
format.html { render :new }
format.json { render json: @campaign.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_campaign
@campaign = Campaign.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def campaign_params
params.require(:campaign).permit(:name, option_ids: [])
end