I am creating a very simple StackOverflow type of website
written in Ruby on Rails. I created four actions in my questions controller and one of them is 'Create'.
I proceeded in the view page index.html.erb and I create a simple_form where I get input(question) from a user.
I get an error (NoMethodError in Questions#index..undefined method `[]' for nil:NilClass)
The question belongs to the current_user and I think that might be the problem. I thought maybe I need to initialize one more variable in order to get my form to work.
Can please someone tell me what am I missing here?
Thank you in advance!
class QuestionsController < ApplicationController
def index
#questions = Question.all
end
def show
#question = Question.find(params[:id])
end
def new
#question = Question.find(params[:user_id])
#question = Question.new
end
def create
#question = Question.new(accepted_params)
if #question.save
redirect_to questions_show_path, notice: 'Question submitted'
else
#question = Question.find(params[:id])
render :new
end
end
<%= simple_form_for #questions, #user do |f| %>
<%= f.input :title %>
<% f.input :content %>
<%= f.submit :submit, class: 'btn btn-secondary'%>
<% end %>
You should use the following code:
def create
#question = Question.new(accepted_params)
if #question.save
redirect_to question_path(#question), notice: 'Question submitted'
else
render :new
end
end
Let me explain:
on a create action there is no params[:id] (because we are creating a new item)
also: we established that saving failed so trying to retrieve it from the database would only make sense on an edit action
third: simple-form will look at the error-messages and incorporate them into the form, so the user can then fix the errors.
and lastly: I fixed your redirect_to to be more "rails"-like, but this depends on your route-definition. I am assuming you have something like resources :questions in your routes (but if you do not give a parameter that could also never work imho)
E.g. if you have a validate_presence_of :name in your model, this could cause a validation-error upon save, and then we could present the field in red in the form when rerendering.
[TYPO in form?]
Lastly, after your comment I noticed it said simple_form_for #questions, #user and that should be either be the singular simple_form_for #question. If you want to edit the question as a nested path for the user, I think the correct form is simple_form_for [#user, #question].
Related
I have Post CRUD. On show.html.erb for Post, I want CRUD for comment. I am using devise for User. I have tried what others have suggested elsewhere on stack overflow but it has not worked. It keeps saying #comment is empty. I'd appreciate your help.
comments controller
def new
#user = current_user
#post = Post.find(params[:post_id])
#comment = #post.comments.new
render :template => 'posts/show'
end
def create
#user = current_user
#post = Post.find(params[:post_id])
#comment = #post.comments.new(post_params)
render :template => 'posts/show'
if #comment.save
redirect_to post_path(post.id), notice: "Success!~"
else
redirect_to post_path(post.id), alert: "Failure!"
end
end
private
def comment_params
params.require(:comment).permit(:text)
end
show.html.erb (within posts folder)
<%= form_for([#user, #post, #comment]) do |form| %>
<p>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
As far as I understand you, you want to have the CRUD actions for comments in the show view of a post. It's called nested routing or just nested models.
From you posts/show view I can see from your form for you also nested the posts inside the users. That's not necessary. As a general guideline, don't nest models more than one level. I guess in your app posts belong to a user, and you're using devise. So by the creation of a post you can just assign the current_user to the post and then you don't need to nest them inside each other.
Now for your questions: Since you have the form for a new comment on the show page of post, you need to have the code from your comments_controller#new in the posts_controller#show. Why? Because you use the instance variable #comment in the form_for. If in your posts_controller there is no such #comment defined,it will throw the error.
Once your form is then filled and submitted a post request to comments_controller#create is made, where you save the code and redirect to the post#show.
UPDATE: I am an idiot. I added the #answers to the users controller instead of the questions controller. now that I changed it to questions controller it is showing. I am having submission errors, but I will start a new thread if I can't figure them out.
I have read a couple dozen of the related questions and tried the solutions without success. I'm wondering if I have my routing set up incorrectly. This is the error I am getting:
First argument in form cannot contain nil or be empty on line 5
Here is my form code. It is an answer form, but it is being shown on the questions index page under a specific question.
<%= form_for #answer do |answer| %> <<< LINE GENERATING ERROR
<%= answer.label :answer, "What do you think?" %>
<%= answer.text_area :answer %>
<%= answer.button %>
<% end %>
Here is my routing information:
resources :answers
get 'answers/new' => 'questions#index'
post 'answers' => 'questions#index'
Here is my answers_controller information:
class AnswersController < ApplicationController
def index
#answers = Answer.all
end
def new
#answer = Answer.new
end
def create
#answer = Answer.new(answer_params)
if #answer.save
redirect_to root
else
render 'new'
end
end
private
def answer_params
params.require(:answer).permit(:answer, :users_id, :questions_id)
end
The first argument to form_for can't be nil - rails can't tell that that you want to create an answer (the instance variable may be called #answer but form for doesn't know the name of the variable passed to it, only the value)
In cases like this, the easiest is something like
<%= form_for Answer.new do %>
...
<% end %>
Alternatively you could leave your view unchanged and set #answer in the controller that is rendering this view (by the sounds of things this is your QuestionsController
UPDATE: It seems like the error was probably due to a devise conflict. I used some content from another app which apparently made devise go nutty and not be able to read user sessions. I'll be starting with a clean install and seeing if I have better luck. Thanks!
I am creating a page which has a single question on it. On that page I have a form where people can answer that question. The form itself just has an answer block and a submit button. However, I want to tie it to both the user submitting the form and the question the answer is linked to. For security I want to do this in the controller, not the view. The answer form is being shown on the questions#index page. I am currently getting the following error:
undefined method `user' for #<AnswersController:0x007fe618e5cc10>
I suspect that if it made it past the user I would get the same for 'question'
The questions#index looks like this:
<div class="home_question">
<h1><%= #daily.question %></h1>
<div class="answer_form">
<%= form_for #answer do |answer| %>
<%= answer.label :answer, "What do you think?" %>
<%= answer.text_area :answer %>
<%= answer.button %>
<% end %>
</div>
</div>
The Questions Controller looks like this:
def index
#daily = Question.find_by(show_month: Time.now.month, show_day: Time.now.day)
#answer = Answer.new
end
The Answers Controller looks like this:
def index
#answers = Answer.all
#answer = Answer.new
end
def new
#answer = Answer.new
end
def create
#answer = Answer.new(answer_params)
#user = user(params[:id])
#question = question(params[:id])
if #answer.save
redirect_to root
else
render 'new'
end
end
private
def answer_params
params.require(:answer).permit(:answer, :users_id, :questions_id)
end
The data currently being passed by the form is:
{"utf8"=>"✓",
"authenticity_token"=>"mA16+dg7+Edzxvu/FVWR5r8PZ9zdNaOyvOwSz1VpOXU=",
"answer"=>{"answer"=>"test"},
"button"=>""}
The error that you're getting is because in the controller you're using the user variable which isn't defined. You want to use the uppercase model name User.
Getting the user id
If this is a logged in user then you can get their id by looking in the session. Usually Rails application will have a helper like this:
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
You don't need this helper if you're using devise -- it's already done for you.
Getting the question id
First make sure that your associated resources are nested. So in our routes.rb file:
resources :questions do
resources :answers
end
This means that to create an answer we'll need to POST /questions/:id/answers.
The form changes to:
<%= form_for [#daily, #answer] do |answer| %>
<%= answer.label :answer, "What do you think?" %>
<%= answer.text_area :answer %>
<%= answer.button %>
<% end %>
and in the controller:
def create
#answer = Answer.new(answer_params)
#answer.user = current_user
#answer.question = Question.find(params[:id])
if #answer.save
redirect_to root
else
render 'new'
end
end
Here's a line from my form, used to create a relationship between two users
<%= form_for(current_user.relationships.build(followed_id: #user.id) do |f| %>
<%= f.hidden_field :followed_id %>
<%= f.submit "follow" %>
Relationship controller create method:
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
I'm trying to figure out how to move the current_user.relationships.build logic out of the form and into the controller, is it possible?
I was able to figure out how to move the logic out of the form.
Basically the object being passed to the form_for helper needs to be initialized. I put the initialization logic into user helper and passed the method to the form_for helper. so this is what you get
user helper method
def initializing_relationships
current_user.relationships.build(followed_id: #user.id)
end
in the form you call initializing_relationships
<%= form_for(initializing_relationships) do |f| %>
This really cleans up the form.
Rails controller:
class VenuesController < ApplicationController
def new
#venue = Venue.new
end
def create
#venue = Venue.new(params[:venue])
if #venue.save
redirect_to root_path
end
end
def update
redirect_to search_path
end
end
Rails form:
<%= form_for(#venue) do |f| %>
<%= f.text_field :foursquare_id %>
<%= f.submit "Save" %>
<% end %>
"foursquare_id" is a column in the "venues" table. usually i import a foursquare id from foursquare but i'm typing in text for testing purposes. i am being redirected to "root_path" before even being given a chance to type into the form.
what is my controller/form missing? thank you in advance
The template form should be used by the new action with new.html.erb as the filename. And you should be going to /venues/new to fill out the form.
The create action is used to submit the completed form, which is why you are getting redirected. You should also modify create to handle a model that couldn't save:
def create
#venue = Venue.new(params[:venue])
if #venue.save
redirect_to root_path
else
render :action => :new
end
end
Or you can use the shorthand for this:
def create
#venue = Venue.new(params[:venue])
#venue.save
respond_with #venue, :location => root_path
end
Your form for creating a new venue should be in venues/new.html.erb which will call the Create action in your controller upon form submit. You shouldn't have a create view in this scenario.