Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails 4 collection_select multiple nested attributes not saving properly

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
like image 796
Justin Avatar asked Dec 12 '22 02:12

Justin


1 Answers

I prefer to do it more convenience way.

 # in your form

 <%= form_for(@post) do |f| %>

##  your other fields
    <%= f.collection_select(:tag_ids, Tag.all, :id, :name, {include_hidden: false}, {multiple: true} ) %><br />
 <% end %>

#in your controller
 def post_params
  params.require(:post).permit([:title, :tag_ids => []])
 end

now instead of two different permitted param list, things will work for both. Removing tag will work without complexity.

Please replace your permitted params values in desired places in your actions.

like image 139
Rubyrider Avatar answered Jan 05 '23 00:01

Rubyrider