Create and push an association at the same time - ruby-on-rails

I have a Word model and a Category model.
Words has_and_belongs_to_many Categories.
Categories has_and_belongs_to_many Words.
Now, I have everything setup and running in the console, for example you can do:
Word.create(title: "Testicles")
testicles = Word.first
Category.create(title: "Genitalia")
genitalia = Category.first
testicles.categories << genitalia
testicles.categories
=> "genitalia"
Now I can get this up and running using forms in the views too, but only if I have separately created the Category in its own form on a separate page, and same with the Word. Then in the Word show view I can create a form to assign the category to it.
HOWEVER... what I really want to do is to do all this at the same time when I create the Word i.e. on the 'new word' view.
I'm having big problems working out how to do this. I think I'm right in saying that I can only have one form and one submit in that view, so I think I somehow have to send everything from that form to, say, the WordsController, and work some magic in there, but exactly what to do here is giving me big headaches. Can anyone help?
I haven't created a User model or setup authentication yet, so there are no obstacles in that respect.
models/word.rb:
class Word < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :categories
validates :title, presence: true
end
models/category.rb:
class Category < ActiveRecord::Base
has_and_belongs_to_many :words
validates :title, presence: true
end
schema.rb:
ActiveRecord::Schema.define(version: 20150529144121) do
create_table "categories", force: :cascade do |t|
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "categories_words", id: false, force: :cascade do |t|
t.integer "category_id"
t.integer "word_id"
end
add_index "categories_words", ["category_id"], name: "index_categories_words_on_category_id"
add_index "categories_words", ["word_id"], name: "index_categories_words_on_word_id"
create_table "words", force: :cascade do |t|
t.string "title"
t.text "description"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "words", ["user_id"], name: "index_words_on_user_id"
end
After experimenting with various form_tag wizardry (and failing badly), at the moment I'm using this form:
<%= form_for(#word) do |f| %>
<% if #word.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#word.errors.count, "error") %> prohibited this word from being saved:</h2>
<ul>
<% #word.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title, 'Word' %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description, 'Definition' %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :categories, 'Category' %><br>
<%= f.text_field :categories %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In the view, the form has:
#<Category::ActiveRecord_Associations_CollectionProxy:0x007f16dd834820>
in the 'Category' box, but this can be cleared and your own category inputted. When submitting the form with all the fields filled in, I get a NoMethodError.

So basically you want to create both a word and a category at the same time, and link them. If the classical solutions (for example using the nested_form gem) don't do exactly what you want, you can try this approach.
You really want a custom view/controller for this and do the business in your controller as you suggest. I suggest that instead you used a simple form_tag where you can add some fieldsets.
View
<%= form_tag your_custom_route_path, :html => {:class => "form-horizontal"} do |form| %>
<%= fields_for :word, #word do |f| %>
<%= f.text_field :title %>
<% end %>
<%= fields_for :category, #category do |f| %>
<%= f.text_field :title %>
<% end %>
<% end %>
routes
post '/yourRoute', to: 'your_controller#your_action_create', as: 'your_custom_route'
Controller featuring some actions
class YourController < ApplicationController
# new
def your_action_new
#word = Word.new
#category = Category.new
end
# Post
def your_action_create
#word = Word.new(word_params)
#category = Category.new(category_params)
if #word.save and #category.save
#word.categories << #category
#word.save
end
end
private
def words_params
params.require(:word).permit(:title, ...)
end
def category_params
params.require(:category).permit(:title...)
end

Thanks to Cyril DD's help, I've expanded on that and created a form and custom controller that will create a new Word with a new Category assigned to it and/or the user can assign existing Categories to that new Word.
_form.html.erb:
<%= form_tag(controller: "new_word", action: "create_word_and_category", method: "post") do %>
<% if #word.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#word.errors.count, "error") %> prohibited this category from being saved:</h2>
<ul>
<% #word.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= fields_for :word, #word do |word_form| %>
<div class="field">
<%= word_form.label(:title, "Word:") %><br>
<%= word_form.text_field(:title, id: "new_word", required: true) %>
</div>
<div class="field">
<%= word_form.label(:description, "Definition:") %><br>
<%= word_form.text_area(:description) %>
</div>
<% end %>
<%= fields_for :category, #category do |category_form| %>
<% if Category.count > 0 %>
<div class="field">
<%= category_form.label(:title, "Choose from existing Categories:") %><br>
<%= category_form.collection_check_boxes(:category_ids, Category.all, :id, :title) %>
</div>
<% end %>
<h4>AND/OR...</h4>
<div class="field">
<%= category_form.label(:title, "Create and Use a New Category:") %><br>
<%= category_form.text_field(:title) %>
</div>
<% end %>
<div class="actions">
<%= submit_tag("Create") %>
</div>
<% end %>
new_word_controller.rb (it's not completely finished yet, but it 'does what it says on the tin'):
class NewWordController < ApplicationController
def create_word_and_category
#word = Word.new(word_params)
if #word.save
(params["category"])["category_ids"].each do |i|
next if i.to_i == 0
#word.categories << Category.find(i.to_i) unless #word.categories.include?(Category.find(i.to_i))
end
if category_params.include?(:title) && ((params["category"])["title"]) != ""
#word.categories << Category.new(title: (params["category"])["title"])
end
end
if #word.save
redirect_to words_path, notice: 'Word was successfully created.'
else
redirect_to new_word_path, notice: 'A valid word was not submitted.'
end
end
private
# Use callbacks to share common setup or constraints between actions.
# def set_word
# #word = Word.find(params[:id])
# end
# Never trust parameters from the scary internet, only allow the white list through.
def word_params
params.require(:word).permit(:title, :description, :user_id)
end
def category_params
params.require(:category).permit(:title, :category_ids, :category_id)
end
end
In my routes.rb:
post 'create_word_and_category' => 'new_word#create_word_and_category'
I'm having going to place that controller code into the old words_controller, because I don't see a need to have it in a separate controller like this. If anyone has any thoughts/critique, great. And if anyone can help me write an rspec controller test for this controller code, even better! I'm having trouble with that.

Related

Where is my "unpermitted parameter: :passenger" Rails error coming from?

I am building a flight booking app with Rails that lets you select airports, date and number of passengers. Once you select the airports and dates, it gives you radio buttons to select which flight you want and, once you click submit, you are taken to a booking confirmation page where you are asked to provide passenger info.
The confirmation page(bookings#new) has a nested form to include passengers in the booking object. To do this, I have first set the following models and associations:
class Passenger < ApplicationRecord
belongs_to :booking
end
class Booking < ApplicationRecord
belongs_to :flight
has_many :passengers
accepts_nested_attributes_for :passengers
end
And the relevant migrations that result in the following schema tables:
create_table "bookings", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "flight_id"
t.integer "passenger_id"
end
create_table "passengers", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "booking_id"
t.index ["booking_id"], name: "index_passengers_on_booking_id"
end
From what I understand, the flow goes like this:
User selects flight -> User submits flight, goes to Booking#new through the #new method on my controller:
class BookingsController < ApplicationController
def new
#booking = Booking.new
#flight = Flight.find(params[:flight_id])
params[:passengers_number].to_i.times do #params passed from select flight page
#booking.passengers.build
end
end
Then, the form I built takes over on new.html.erb:
<%= form_with model: #booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: #flight.id %>
<% #booking.passengers.each_with_index do |passenger, index| %>
<%= f.fields_for passenger, index: index do |form| %>
<h4><%= "Passenger #{index+1}"%> <br> </h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
I fill it in with names and emails, click 'Confirm details' and I get this error on my terminal:
Unpermitted parameter: :passenger
Why? I have set accepts_nested_attributes_for :passengers on my Booking model, my booking_params method is:
def booking_params
params.require(:booking).permit(:flight_id,
:passengers_attributes => [:name, :email, :passenger_id, :created_at, :updated_at])
end
and my #create method is:
def create
#booking = Booking.new(booking_params)
respond_to do |format|
if #booking.save
format.html { redirect_to #booking, notice: "booking was successfully created." }
format.json { render :show, status: :created, location: #booking }
else
format.html { redirect_to root_path, alert: "booking failed, #{#booking.errors.full_messages.first}" , status: :unprocessable_entity }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
Is there something I am not permitting properly? Note that if I set booking_params as params.require(:booking).permit! it gives me an unknown attribute 'passenger' for Booking error. But I have defined associations and database on passenger and booking, at least to my knowledge.
Thanks in advance
Edit: The server log that generates the error is:
Started POST "/bookings" for ::1 at 2021-08-27 17:52:17 +0300
Processing by BookingsController#create as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "booking"=>{"flight_id"=>"5", "passenger"=>{"0"=>{"name"=>"Jason Smason", "email"=>"jason#ymail.com"}, "1"=>{"name"=>"Joe Smith", "email"=>"Joe#smith.com"}}}, "commit"=>"Confirm details"}
Unpermitted parameter: :passenger
Edit2: I followed PCurell's advice and changed my fields_for to <%= f.fields_for :passengers, passenger, index: index do |form| %> and my booking params to :passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
That generated a different error: Unpermitted parameter: passengers_attributes'. So I changed my controller's booking_params` to:
def booking_params
params.require(:booking).permit(:flight_id,
:passengers_attributes => [:name, :email, :passenger_id, :created_at, :updated_at],
:passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
end
With that, I successfully managed to create a booking with 2 passengers. However, the passengers are blank; their name and email are nil. The log says:
Parameters: {"authenticity_token"=>"[FILTERED]", "booking"=>{"flight_id"=>"1", "passengers_attributes"=>{"0"=>{"0"=>{"name"=>"John Smith", "email"=>"John#smith.com"}}, "1"=>{"1"=>{"name"=>"Burger King", "email"=>"bk#bk.com"}}}}, "commit"=>"Confirm details"}
Unpermitted parameter: :0
Unpermitted parameter: :1
I might be able to hardcode :0 and :1 to pass, but surely that's not the Rails way. Is there a way to dynamically let them in? Or am I doing the whole thing wrong?
Your usage of fields_for is incorrect. When you look at the example in the guide you will notice that there is no need to wrap it with an .each if used for a collection.
10.2 Nested Forms
The following form allows a user to create a Person and its
associated addresses.
<%= form_with model: #person do |form| %>
Addresses:
<ul>
<%= form.fields_for :addresses do |addresses_form| %>
<li>
<%= addresses_form.label :kind %>
<%= addresses_form.text_field :kind %>
<%= addresses_form.label :street %>
<%= addresses_form.text_field :street %>
...
</li>
<% end %>
</ul>
<% end %>
When an association accepts nested attributes fields_for renders its block once for every element of the association. In particular,
if a person has no addresses it renders nothing. A common pattern is
for the controller to build one or more empty children so that at
least one set of fields is shown to the user. The example below would
result in 2 sets of address fields being rendered on the new person
form.
def new
#person = Person.new
2.times { #person.addresses.build }
end
When applying this to your code, removing the .each wrapper and changing passenger into :passengers should do the trick. You can access the index through the FormBuilder instance (form) passed to the fields_for block.
<%= form_with model: #booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: #flight.id %>
<%= f.fields_for :passengers do |form| %>
<h4>Passenger <%= form.index + 1 %></h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
As #Rockwell Rice mentioned in his comment:
The problem here is that you are permitting the wrong param.
def booking_params
params.require(:booking).permit(:flight_id,
:passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
end
Should work.
Although you might encounter another error.
I think that you are constructing your fields_for wrong.
This should be what you are looking for (and you will not have to change the booking_params)
<%= form_with model: #booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: #flight.id %>
<% #booking.passengers.each_with_index do |passenger, index| %>
<%= f.fields_for :passengers, passenger, index: index do |form| %>
<h4><%= "Passenger #{index+1}"%> <br> </h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
The above should work.
If you don't care too much about the index this would work as well:
<%= form_with model: #booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: #flight.id %>
<%= f.fields_for #booking.passengers do |form| %>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>

Why is my party not being created and saved to the database?

I have my parameters whitelisted and when I look at the output of party_params I see that they are permitted but when I got to save the instance into the database it gives me a rollback transaction in the console. I've tried just create, create then save, new then save. Is there something I am missing?
#controller
class PartiesController < ApplicationController
def new
#party = Party.new
end
def create
#party = Party.create(party_params)
redirect_to party_path(#party)
end
private
def party_params
params.require(:party).permit(
:name,
:trainer_id,
:pokemon1_id
)
end
end
#model
class Party < ApplicationRecord
belongs_to :trainer
belongs_to :pokemon
validates :name, presence: true
end
#view
<h1>Create a New Pokemon Party</h1>
<p>Select 6 Pokemon</p>
<%= form_for(#party) do |f| %>
<label>Party Name:</label>
<%= f.text_field :name %><br>
<label>Trainer Name:</label>
<%= collection_select(:party, :trainer_id, Trainer.order(:id), :id, :name, include_blank: true) %><br>
<label>Pokemon:</label>
<%= collection_select(:party, :pokemon1_id, Pokemon.order(:id), :id, :nickname, include_blank: false) %><br>
<%= f.submit %>
<% end %>
#schema
create_table "parties", force: :cascade do |t|
t.string "name"
t.integer "pokemon1_id"
t.integer "trainer_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
Lets start with the models. If you want a party to be able to include multiple pokemon you need to place the foreign key in the other model:
class Party < ApplicationRecord
belongs_to :trainer
has_many :pokemons # references the pokemons.party_id column
end
class Pokemon < ApplicationRecord
belongs_to :party # pokemons needs a `party_id` column
end
class AddPartyToPokemons < ActiveRecord::Migration
def change
add_reference :pokemons, :party, null: false, foreign_key: true
remove_column :parties, :pokemon1_id
end
end
This is very simplefied and assumes that Pokemon is an individual Pokemon and not the entire species and can only belong to a single party. Otherwise you need a many-to-many assocation with a join table/model.
In your controller you need to check if creating the record was actually successful and respond accordingly:
class PartiesController < ApplicationController
def new
#party = Party.new
end
def create
#party = Party.new(party_params)
if #party.save
redirect_to #party
else
render :new
end
end
private
def party_params
params.require(:party).permit(
:name,
:trainer_id,
pokemon_ids: []
)
end
end
If the user input is invalid this will render the app/parties/new.html.erb view and respond with it.
While you could use pry or byebug to step into the controller and check the errors you want to display the validation errors to the user in the view anyways so that they know what to actually do to correct the form:
<h1>Create a New Pokemon Party</h1>
<p>Select 6 Pokemon</p>
<%= form_for(#party) do |f| %>
<% if #party.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#party.errors.count, "error") %> prohibited this party from being saved:</h2>
<ul>
<% #article.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<%
# group labels and inputs in an element instead of abusing BR tags
# this lets you style the content with CSS
-%>
<div class="field">
<%# use f.label as it sets the `for=` attribute which is important for screen readers -%>
<%= f.label :name, 'Party Name:' %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :trainer_id, 'Trainer Name:' %>
<%# call the helper on the form builder to bind the input to the model -%>
<%= f.collection_select(:trainer_id, Trainer.order(:id), :id, :name, include_blank: true) %>
</div>
<div class="field">
<%= f.label :pokemon_ids, 'Pokemon:' %>
<%# call the helper on the form builder to bind the input to the model -%>
<%= f.collection_select(:pokemon_ids, Pokemon.order(:id), :id, :nickname, include_blank: false, multiple: true) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Note f.collection_select(:pokemon_ids, ...). This is a special setter/getter is generated by has_many :pokemons.

NoMethodError using Rails 4.0 and nested forms with cocoon

I'm learning to use Rails 4.0 and I'm using Cocoon to create nested forms for a simple Polling app.
The user should be able to add a new question and then add as many answers as they'd like.
I've got the nested forms working but when I try to save the Poll and i'm getting an error that says NoMethodError in PollsController#create - undefined method ``answer' for #<Poll:0x007fba59a70dd0>
Here's the relevant information from my Polls_Controller:
before_action :set_poll, only: [:show, :edit, :update, :destroy]
def create
#poll = Poll.new(poll_params)
respond_to do |format|
if #poll.save
format.html { redirect_to #poll, notice: 'Poll was successfully created.' }
format.json { render :show, status: :created, location: #poll }
else
format.html { render :new }
format.json { render json: #poll.errors, status: :unprocessable_entity }
end
end
end
private
def poll_params
params.require(:poll).permit(:question, :expires, answers_attributes: [:id, :answer, :_destroy])
end
Polls Model
class Poll < ActiveRecord::Base
has_many :answers, :class_name => "Answer"
accepts_nested_attributes_for :answers, reject_if: :all_blank, allow_destroy: true
validates :answer, presence: true
end
And the Answers model
class Answer < ActiveRecord::Base
belongs_to :poll
end
Here are the two .erb partials containing the Poll form and the Answer (nested) form.
_form.html.erb
<%= form_for(#poll) do |f| %>
<% if #poll.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#poll.errors.count, "error") %> prohibited this poll from being saved:</h2>
<ul>
<% #poll.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-group">
<%= f.label :question %><br>
<%= f.text_field :question, class: "form-control" %>
</div>
<div class="form-group" id="answers">
<%= f.fields_for :answers do |answer| %>
<%= render 'answer_fields', f: answer %>
<% end %>
<div class="links">
<%= link_to_add_association 'Add Answer', f, :answers, class: "btn btn-default add-button" %>
</div>
</div>
<div class="form-group">
<%= f.label :expires %><br>
<%= f.datetime_select :expires %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
_answer.html.erb
<div class="nested-fields form-group">
<div class="field">
<%= f.label :answer %>
<br/>
<%= f.text_field :answer, class: "form-control" %>
</div>
<%= link_to_remove_association "remove answer", f, class: "form-button btn btn-default" %>
</div>
I've been staring at this for far too long and even though it's a simple idea, my brain isn't seeing the issue. Any ideas?
Edit Here is my Schema
ActiveRecord::Schema.define(version: 20151104213600) do
create_table "answers", force: :cascade do |t|
t.text "answer"
t.integer "poll_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "answers", ["poll_id"], name: "index_answers_on_poll_id"
create_table "polls", force: :cascade do |t|
t.string "question"
t.datetime "expires"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
I have run into this problem myself, and by pre-building the associated relation, it worked like a charm, doing this:
def new
#poll = Poll.new
#poll.answers.build
end

cocoon gem not passing parameters

So although I have used cocoon successfully before, I'm still relatively new and for whatever reason can't seem to get it to pass through the parameters (I've tried with two different applications and on fedora 22 and mac 10.10.4).
For context I've been using the standard rails forms in .erb and have both :post and :post_items which only currently have a description. I'm using cocoon 1.2.6.
So in application.js I have
//= require cocoon
in post.rb
class Post < ActiveRecord::Base
has_many :post_items
accepts_nested_attributes_for :post_items, :reject_if => :all_blank, :allow_destroy => true
validates :title, :post_items, presence: true
validates :title, length: {maximum: 255}
end
in post_item.rb
class PostItem < ActiveRecord::Base
belongs_to :post
end
and my relevant controllers are (posts_controller.rb):
def index
#post = Post.new
end
def create
params[:post][:ip_address] = request.remote_ip
#post = Post.create(post_params)
if #post.save
flash[:success] = "Your post was successfully created"
redirect_to #post
else
flash[:failure] = "There was an error saving your post"
render 'index'
end
end
private
def find_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :tags, :hits, :ip_address, post_items_attributes: [:id, :description, :_destroy])
end
And finally in my views I have (_form.html.erb)
<%= form_for #post, html: {multipart: true} do |f| %>
<% if #post.errors.any? %>
<p>There were <%= #post.errors.count %> errors</p>
<% #post.errors.full_messages.each do |msg| %>
<p><%= msg %></p>
<% end %>
<% end %>
<!-- a bunch of fields here -->
<div class="six columns">
<h3>Add images</h3>
<div id="post_items">
<% f.fields_for :post_items do |post_item| %>
<%= render 'post_item_fields', f: post_item %>
<% end %>
<div class="links">
<%= link_to_add_association 'Add Image', f, :post_items, class: "add-button" %>
</div>
</div>
<%= f.button :submit, class: "button submit-button" %>
<% end %>
and lastly _post_item_fields.html.erb
<div class="nested-fields">
<div class="field">
<%= f.label :description %>
<%= f.text_area :description %>
</div>
<%= link_to_remove_association "Remove", f %>
</div>
There are CSS files that modify the html but I have no js other than what's automatically built. I've literally been stuck on this problem for days now and I can't figure out what's wrong. I have tried the post.rb without the validates code but it still doesn't work.
The only lead I have is that when you print out the parameters it has already dropped the post_items parameters and for the life of me I can't figure out why.
Thanks for the help!
EDIT: for the sake of information I've added my migrations.
in db/migrate/20150722191917_create_post_items.rb
class CreatePostItems < ActiveRecord::Migration
def change
create_table :post_items do |t|
t.string :description
t.belongs_to :post, index: true, foreign_key: true
end
end
end
and in db/migrate/20150722173629_create_posts.rb
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.string :tags
t.integer :hits, null: false, default: 0
t.string :ip_address
t.timestamps null: false
end
add_index :posts, :ip_address
end
end
Also if it matters I didn't use scaffold when generating them
Well I think I finally figured out what's wrong (although I don't really understand what we're supposed to do to get around it) is that once I got rid of div class="six columns" it worked, so apparently that was interfering with the cocoon gems ability to parse the html.
Thanks everyone for all the help!
EDIT: to clarify I had to change _form.html.erb to:
<%= form_for #post, html: {multipart: true} do |f| %>
<% if #post.errors.any? %>
<p>There were <%= #post.errors.count %> errors</p>
<% #post.errors.full_messages.each do |msg| %>
<p><%= msg %></p>
<% end %>
<% end %>
<!-- a bunch of fields here -->
<h3>Add images</h3>
<div id="post_items">
<% f.fields_for :post_items do |post_item| %>
<%= render 'post_item_fields', f: post_item %>
<% end %>
<div class="links">
<%= link_to_add_association 'Add Image', f, :post_items, class: "add-button" %>
</div>
</div>
<%= f.button :submit, class: "button submit-button" %>
<% end %>
So I guess it was a little my fault as the error would have been easier to spot if I had used the full html instead of parsing it for the cocoon-relevant bits but there it is regardless. (basically the moral of this story is that you can't have div's inside of the form)

Setting Foreign key params Relationship in rails

I've searched a lot , found similar questions , but any seem to fit , or i did not understood right.
i have 3 models , i choose a bad name for one model, that is for Tv Shows , and you may confuse the Show model with show method and view .
Show.rb
class Show < ActiveRecord::Base
has_many :seasons
belongs_to :user
has_many :episodes , through: :seasons
accepts_nested_attributes_for :seasons
attr_accessible :name,:status,:duration
end
Season.rb
class Season < ActiveRecord::Base
belongs_to :show
has_many :episodes
accepts_nested_attributes_for :episodes
attr_accessible :order,:status
end
Episode.rb
class Episode < ActiveRecord::Base
belongs_to :season
attr_accessible :number
end
My forms for each model are separeted, what i wanna do is set the foreigns keys for each one automatically. So , in the view of my Show i wanna create a season that will be stored in that Show.
Shows/show.html.erb
p id="notice"><%= notice %></p>
<% #seasons = Season.all %>
<% #episodes= Episode.all%>
<p>
<strong>Name:</strong>
<%= #show.name %>
</p>
<p>
<strong>Status:</strong>
<%= #show.status %>
</p>
<p>
<strong>Episode Duration:</strong>
<%= #show.Episode_Duration %>
</p>
<% #seasons.where(:show_id => #show.id).each do |season| %>
<tr>
<td><%= season.order %></td>
<td><%= season.status %></td>
<h3>episodios</h3>
<hr>
<% #episodes.where(:season_id => season.id).each do |episode| %>
<td> <%= episode.number%></td>
<%end%>
<hr>
<td><%= link_to 'episode', episode_new_path(season.id)%></td>
</tr>
<br>
<% end %>
<h1><%=#show.id%></h1>
<h1><%=#show.episodes.count%></h1>
<h1></h1>
**<%= link_to 'create seasons', season_new_path(#show.id) %>**
<%= link_to 'Edit', edit_show_path(#show) %> |
<%= link_to 'Back', shows_path %>
In that lasts line, i'm passing #show.id for create a season, i want use that #show.id as my foreign key :show_id for that season. how i use that id in my params?
I saw some posts and i tried this , but didn't worked , heres the controller(only the part that i think is useful.)
seasons_controller.rb
def create
#season = Season.new(season_params)
#season.show_id = params[:id]
#season.save
end
respond_to do |format|
if #season.save
format.html { redirect_to #season, notice: 'Season was successfully created.' }
format.json { render :show, status: :created, location: #season }
else
format.html { render :new }
format.json { render json: #season.errors, status: :unprocessable_entity }
end
end
def season_params
params.require(:season).permit(:order, :status)
end
EDIT
My routes are:
Routes.rb
devise_for :users
resources :episodes
resources :seasons
resources :shows
root 'shows#index'
get 'seasons/create/:id' => 'seasons#new', as: :season_new
get 'episodes/create/:id' => 'episodes#new', as: :episode_new
put 'subscribe_show/:id' => 'shows#subscribe', as: :user_subscribe_show
put 'unsubscribe_show/:id' => 'shows#unsubscribe', as: :user_unsubscribe_show
get 'user/dashboard/' => 'users#index', as: :user_dashboard
And my forms are:
seasons/form.html.erb
<%= form_for(#season) do |f| %>
<% if #season.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#season.errors.count, "error") %> prohibited this season from being saved:</h2>
<ul>
<% #season.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :order %><br>
<%= f.number_field :order %>
</div>
<div class="field">
<%= f.label :status %><br>
<%= f.text_field :status %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Show/form.html.erb
<%= form_for(#show) do |f| %>
<% if #show.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#show.errors.count, "error") %> prohibited this show from being saved:</h2>
<ul>
<% #show.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>
<div class="field">
<%= f.label :status %><br>
<%= f.text_field :status %>
</div>
<div class="field">
<%= f.label :Episode_Duration %><br>
<%= f.text_field :Episode_Duration %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
EDIT 2:
schema.rb
create_table "episodes", force: :cascade do |t|
t.integer "number"
t.integer "season_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "seasons", force: :cascade do |t|
t.integer "order"
t.string "status"
t.integer "show_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "watched"
end
create_table "shows", force: :cascade do |t|
t.string "name"
t.string "status"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "Episode_Duration"
t.integer "user_id"
end
Migrations
class AddUserIdtoShow < ActiveRecord::Migration
def change
add_index :shows , :user_id
end
end

Resources