NoMethodError using Rails 4.0 and nested forms with cocoon - ruby-on-rails

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

Related

Could not save nested form in rails 5.1

I used nested_form gem and I am trying to build a form which has fields from two tables(Project, Question).
My model:
class Project < ApplicationRecord
has_many :questions
accepts_nested_attributes_for :questions
end
class Question < ApplicationRecord
belongs_to :project
end
My controller:
class ProjectsController < ApplicationController
layout 'application'
def index
#projects = Project.all
end
def show
#project = Project.find(params[:id])
end
def new
#project = Project.new
#questions = #project.questions.build
end
def create
#project = Project.new(project_params)
#project.save
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
private
def project_params
params.require(:project).permit(:name, question_attributes: [:id, :content, :_delete])
end
end
My view:
<%= nested_form_for(#project) do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% #project.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>
<%= f.fields_for :questions do |builder| %>
<%= render "question_fields", :ff => builder %>
<% end %>
<p>
<%= f.link_to_add "Add a questions",:questions %>
</p>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And my schema file :
create_table "projects", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "questions", force: :cascade do |t|
t.integer "project_id"
t.string "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["project_id"], name: "index_questions_on_project_id", using: :btree
end
And _question_fields file is :
<p>
<%= ff.label :content, "Question" %>
<%= ff.text_area :content%>
<%= ff.link_to_remove "Remove this task"%>
</p>
Table Project will be saved but the table Question could not be saved.Why?
After change this line of code
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :_delete])
end
I get the following error:
1 error prohibited this project from being saved:
Questions project must exist
I applied the change too ,but this time nothing could not be saved.
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :project_id, :_delete])
end
The issue is with the project_params. As you have has_many :questions, the question_attributes should be changed to questions_attributes
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :_delete])
end
Update:
Questions project must exist
Either permit project_id in questions_attributes
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :project_id, :_delete])
end
or set optional: true on the association
class Question < ApplicationRecord
belongs_to :project, optional: true
end

undefined method `user_name' for nil:NilClass when adding comments form for

everything was working until I add the form_for for creating comments and I get this error undefined method `user_name' for nil:NilClass...
I searching for hours for solution but in vain..
here is my posts views index file with the form I added for creating the comments:
<div class="row">
<div class="col-md-12">
<%= render 'form' %>
<div id="posts" class="transitions-enabled">
<% #posts.each do |post| %>
<div class="box box-1 panel panel-default">
<div class="panel-body">
<%= link_to image_tag(post.user.avatar.url, size: "50x50", class: "img-circle"), profile_path(post.user.user_name) %>
<ul class="posts-shows">
<li><strong><%= link_to post.user.user_name, profile_path(post.user.user_name) %></strong></li>
<li><small><%= link_to "#{time_ago_in_words(post.created_at)} ago", post_path(post), class: "time-link" %> </small></li>
</ul>
<p class="disc-posts"><%= post.description %></p>
<%= link_to image_tag(post.image.url(:large), class: "img-responsive img-in" ) %><br/>
<% if post.user == current_user %>
<div><%= link_to "Edit", edit_post_path(post) %> | <%= link_to "delete", post, method: :delete, data: {confirm: "Are you sure?"} %> </div>
<% else %>
<div><%= link_to "Repost", repost_post_path(post), method: :post, data: { confirm: "Are you sure?"} if user_signed_in? %></div>
<% end %>
</div>
<%= form_for([post, post.comments.build]) do |f| %>
<p>
<%= f.label :content %><br>
<%= f.text_area :content, class: "form-control" %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<% if post.comments.present? %>
<div class="panel-footer">
<% post.comments.each do |comment| %>
<%= link_to image_tag(post.user.avatar.url, size: "30x30", class: "img-circle"), profile_path(comment.user.user_name) %>
<%= link_to comment.user.user_name, profile_path(comment.user.user_name), class: "username-size" %>
<%= comment.content %>
<% if comment.user == current_user %>
<%= link_to "delete", post_comment_path(post, comment), method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
here is the form_for alone:
<%= form_for([post, post.comments.build]) do |f| %>
<p>
<%= f.label :content %><br>
<%= f.text_area :content, class: "form-control" %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
and here is my comment, user and post model that shows the associations :
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
.........................
class Post < ActiveRecord::Base
validates_presence_of :description
belongs_to :user
has_many :comments, dependent: :destroy
end
......................
class User < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :posts, dependent: :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :user_name, presence: true, length: { minimum: 4, maximum: 16 }
end
and my comments controller:
class CommentsController < ApplicationController
before_action :set_post
def index
#comments = #post.comment.all
end
def new
#comment = #post.comments.build(comments_params)
end
def create
#comment = #post.comments.build(comments_params)
#comment.user_id = current_user.id
if #comment.save
redirect_to :back
else
flash[:alert] = "Check the comment form"
render root_path
end
end
def edit
end
def update
end
def destroy
#comment = #post.comments.find(params[:id])
#comment.destroy
flash[:success] = "Comment deleted :("
redirect_to root_path
end
private
def comments_params
params.require(:comment).permit(:content)
end
def set_post
#post = Post.find(params[:post_id])
end
end
my schema:
create_table "comments", force: :cascade do |t|
t.integer "user_id"
t.integer "post_id"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
add_index "comments", ["user_id"], name: "index_comments_on_user_id"
create_table "posts", force: :cascade do |t|
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image"
t.integer "user_id"
t.integer "original_post_id"
end
add_index "posts", ["user_id"], name: "index_posts_on_user_id"
seems like few comments don't have user_id in this line
<%= link_to comment.user.user_name, profile_path(comment.user.user_name), class: "username-size" %>
Try destroying the comments with user_id having nil value
Comment.destroy_all(user_id: nil)
Are you sure your post table have user_id or others foreign key ?
You can use :
belongs_to :user, :foreign_key => 'user_id' at post.rb model
And :
has_many :posts, :foreign_key => 'user_id' at user.rb
I'm pretty new to Rails myself, but I've worked through similar errors a dozen times. This bit appears to be a problem:
profile_path(post.user.user_name)
Earlier in the same line of code, you use:
link_to post.user.user_name
but that part seems okay, because it's just the displayed text.
In the actual link, I don't think you should include the user_name. Try simply using "post.user" instead.

has many through checkboxes?

I have a many-many relationship with students and organizations. When creating a new student, I want to have a checkbox to select one or more organizations and save that. How do I do this? What does the MVC look like specifically? I can't find any online resource that gives me the whole overview.
Updated code:
in my form partial:
<%= simple_form_for (#student) do |f| %>
<div class="field">
<%= f.label :organization_ids %><br />
<%= collection_check_boxes :student, :organization_ids, Organization.all, :id, :name %>
</div>
<div class="actions">
<button class="btn btn-primary" type="submit">Save</button> <%= link_to "Cancel", :back, {:class=>"btn btn-primary"} %>
</div>
<% end %>
controller:
def update
#student = Student.find(params[:id])
if Student.save_existing(params[:id], params[:student])
flash[:notice] = "Student was successfully updated!"
redirect_to students_path
else
flash[:error] = "Student failed to update."
redirect_to students_path
end
end
def student_params
params.require(:student).permit(:name, :organization_ids => [])
end
student table:
create_table "students", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "organization_id"
t.integer "organization_ids"
end
my problem: when i do #student.organization_ids.inspect, it gives me an empty array meaning that the form didn't save my input form checkboxes
You can use collection_check_boxes. Something like below in your student create form would do.
<div class="field">
<%= f.label :organization_ids %><br />
<%= collection_check_boxes(:student, :organization_ids, Organization.all, :id, :name) %>
</div>

Create and push an association at the same time

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.

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