I'm new to rails and I'm having trouble saving nested attributes of a join table using collection_select. I have models post, tag, and post_tagging. post_tagging is a join table.
I want to set multiple tags per post so I attempted to use a multi-select via collection_select, but when I save only the post_id is inserted into the database. Below is my code and the log.
Post.rb
class Post < ActiveRecord::Base
has_many :post_taggings, foreign_key: :post_id, dependent: :destroy
has_many :tags, through: :post_taggings, source: :tag
accepts_nested_attributes_for :post_taggings, reject_if: :all_blank, allow_destroy: true
end
Tag.rb
class Tag < ActiveRecord::Base
has_many :post_taggings, foreign_key: :tag_id, dependent: :destroy
has_many :posts, through: :post_taggings, source: :post
end
post_tagging.rb (I turned off presence validation on tag_id and post_id in the post_tagging model so I could get a log of the POST.)
class PostTagging < ActiveRecord::Base
belongs_to :post
belongs_to :tag
#validates :post_id, presence: true
#validates :tag_id, presence: true
end
posts_controller.rb (abbreviated)
class PostsController < ApplicationController
def new
@post = Post.new
@post.post_taggings.build
end
def new_post_params
params.require(:post).permit(:title, post_taggings_attributes: { :tag_id => [] })
end
def update_post_params
params.require(:post).permit(:title, post_taggings_attributes: [ { :tag_id => [] },
:id, :_destroy ])
end
end
views/post/new.html.erb
<%= form_for(@post) do |f| %>
<%= f.fields_for :post_taggings do | pt | %>
<%= pt.label :post_taggings, "Tags" %><br />
<%= pt.collection_select(:tag_id, Tag.all, :id, :name, {include_hidden: false}, {multiple: true} ) %><br />
<% end %>
The HTML
<select id="post_post_taggings_attributes_0_tag_id" multiple="multiple" name="post[post_taggings_attributes][0][tag_id][]">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
When I save the form I get the following:
Started POST "/posts" for 127.0.0.1 at 2014-12-13 04:22:19 -0800
Processing by PostsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"DaeMJb5b4PcLUz2YfQCjYk1r7pzcMd3NOmhYwEExz2U=", "post"=>{"title"=>"The Title", "post_taggings_attributes"=>{"0"=>{"tag_id"=>["1", "2", "6"]}}}, "commit"=>"Create Post"}
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "posts" ("created_at", "title", "updated_at") VALUES (?, ?, ?) [["created_at", "2014-12-13 12:22:19.789055"], ["title", "The Title"], ["updated_at", "2014-12-13 12:22:19.789055"]]
SQL (0.4ms) INSERT INTO "post_taggings" ("created_at", "post_id", "updated_at") VALUES (?, ?, ?) [["created_at", "2014-12-13 12:22:19.791928"], ["post_id", 16], ["updated_at", "2014-12-13 12:22:19.791928"]]
(2.2ms) commit transaction
Redirected to http://localhost:3000/posts/16
Completed 302 Found in 27ms (ActiveRecord: 3.3ms)
Since it's not working I know I'm doing something wrong. I'm also not confident that the edit case will work.
I feel I'm close since it works with a single select if I change the strong params from
{ :tag_id => [] }
to
:tag_id