I'm having issues with creating a form that will save my has_many :through associations. I've successfully saved by posting json, but the forms just won't work for me yet. The request params created by the form submit just won't work out. Any help pointing me to the solution would help me from losing any more time on this. Thanks up front.
EDITED -- Added forms_for attempt and the created params json that doesn't work as well at the bottom --
Json post request params that works:
{
"author": {
"name": "Author Name",
"post_authors_attributes": [
{"post_id":"1"},
{"post_id":"2"},
{"post_id":"3"}
]
}
}
Rails form generated params that don't save.
{
"author": {
"name": "assd",
"post_authors_attributes": [
"",
"2",
"3"
]
}
}
...and the relevant code samples...
Author Model
class Author < ActiveRecord::Base
has_many :post_authors
has_many :posts, :through => :post_authors
accepts_nested_attributes_for :post_authors
end
Post Model (Currently only working on the Author has many Posts, not the reverse)
class Post < ActiveRecord::Base
end
PostAuthor Model
class PostAuthor < ActiveRecord::Base
belongs_to :post
belongs_to :author
end
Author Controller new/create actions
# GET /authors/new
def new
@author = Author.new
@author.post_authors.build
end
# POST /authors
# POST /authors.json
def create
@author = Author.new(params)
respond_to do |format|
if @author.save
format.html { redirect_to @author, notice: 'Author was successfully created.' }
format.json { render :show, status: :created, location: @author }
else
format.html { render :new }
format.json { render json: @author.errors, status: :unprocessable_entity }
end
end
end
authors/_form.html.erb
<%= form_for(@author) do |f| %>
<% if @author.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@author.errors.count, "error") %> prohibited this author from being saved:</h2>
<ul>
<% @author.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= collection_select(:author, :post_authors_attributes, Post.all, :id, :title,
{include_blank: false, :selected => @author.posts.map(&:id)},
{:multiple => true}) %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Schema
ActiveRecord::Schema.define(version: 20150120190715) do
create_table "authors", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "post_authors", force: :cascade do |t|
t.integer "post_id"
t.integer "author_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
EDIT -- ADDED Details -- Just for due dilligence, I've also tried using a fields_for, but it produces even more messed up json that doesn't save to the database. I have no idea where the "0" key comes from. I'm stuck on this, any help would greatly be appreciated.
fields_for
<div class="field">
<%= f.fields_for :post_authors, @author.post_authors do |posts_form| %>
<%= f.label :Posts %><br>
<%= posts_form.collection_select(:post_id, Post.all, :id, :title,
{include_blank: false, :selected => @author.posts.map(&:id)},
{:multiple => true}) %>
<% end %>
</div>
Produced params to_json
{
"author": {
"name": "test",
"post_authors_attributes": {
"0": {
"post_id": [
"",
"1",
"2",
"3"
]
}
}
}
}
authors/_form.html.erb
:authors_controller.rb
:For anyone fighting the same kind of issue, I finally managed to get this to work with the following collection_select: