Rails: Param is nil - ruby-on-rails

I'm trying to pass some params from a form to a view but all I get is param is missing or the value is empty: quotes. I've checked the database and the input is saved there but for some reason the data becomes nil somewhere along the way to the view.
I'm passing along the :quotes parameter from the view to the controller, and that should be it, shouldn't it?
quotes_controller.rb
class QuotesController < ApplicationController
def new
end
def create
#quote = Quote.new(quote_params)
#quote.save
redirect_to #quote
end
def show
#quote = Quote.find(quote_params[:id])
end
private
def quote_params
params.require(:quotes).permit(:title, :text)
end
end
new.html.erb
<h2>Add Quote</h2>
<%= form_for :quotes, url: quotes_path do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
show.html.erb
<h2>Saved Quotes</h2>
<p>
<strong>Title:</strong>
<%= #quote.title %>
</p>
<p>
<strong>Text:</strong>
<%= #quote.text %>
</p>
<% end %>
I'm using the Rails Dev Box if that makes any difference.

Since you mentioned the records are indeed getting saved to the database, new and create actions should not be a problem. However, when you do redirect_to #quote the id of #quote is available as params[:id] in show. So I think, modifying the show action in controller as below should work.
def show
#quote = Quote.find(params[:id])
end
On another note, you should consider modifying your create action to account for submissions for new quotes that don't pass the validations or don't get saved to the database.
def create
#quote = Quote.new(quote_params)
if #quote.save
flash[:success] = "Successfully created the new quote..."
redirect_to #quote
else
render 'new'
end
end
This would result in a friendly flash message to the user on the redirected page if the quote gets created. If not, it renders quotes#new to try another submission.

The bug is the view for new action. You don't have anywhere quotes instance variables set. Actually there should be quote there, but there is not.
Add in new:
#quote = Quote.new
then use:
form_for(#quote)
in your new view.

Related

Wrong number of arguments error (0 for 1) in Ruby on Rails 4 when creating a form for user submission

at the moment I am attempting to create a form for my website that will allow for users to input information and then the information with be POST'ed to my database for storage. I am a new ruby on rails developer so keep that in mind.
I was able to get to the point where the user could see the form and type in information but once they hit the submit button I recieve an error, and that error is
ArgumentError in StudentsController#create
wrong number of arguments (0 for 1) in app/controllers/students_controller.rb:13:in `create'
The parameters that were sent were the following
{"utf8"=>"✓",
"authenticity_token"=>"bLalQ9Ek5ziaGiGHj03AGPCTIABAgcT+o4eTgN44qv44dxNDlrGA0h2u5BSTQVTMh+YgA/mLPQee05lT7mxCsw==",
"student"=>{"first_name"=>"Andrew",
"last_name"=>"Terra"},
"commit"=>"Submit"}
Below is my students_controller.rb file.
class StudentsController < ApplicationController
def index
#students = Student.all
end
def new
#student = Student.new
end
def create
#student = Student.new(params.require[:student])
if #student.save
redirect_to students_path
end
end
def destroy
#student = Student.find_by_id(params[:id])
if #student.destroy
redirect_to students_path
end
end
end
Below is my views/students/_form.html.erb file
<%= form_for #student do |f| %>
<p>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
</p>
<p>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
</p>
<%= f.submit "Submit" %>
<% end %>
Below is my /views/students/index.html.erb file
<%= link_to "Create new information", new_student_path %> <br /> <hr>
<% #students.each do |fo| %>
Firstname: <%= fo.first_name %> <br />
Lastname: <%= fo.last_name %> <br />
<%= link_to "Delete info?", student_path(student), :data=>{:confirm=>"Are you sure ?"}, :method=> :delete %>
<br />
<hr>
<% end %>
Finally, here is my /views/students/new.html.erb file
Enter new info
<hr>
<%= render :partial => "form" %>
And I did remember to put resources :students in my routes file. I searched around and found other people who had previously had this problem but none of the solutions worked on the code that I have written. So I was wondering if anyone could point me in the direction of where the bug is and how exactly I can fix it. Thank you.
You need to add a new private method:
private
def student_params
params.require(:student).permit(:first_name, :last_name)
end
And then as said before change your create method to:
def create
#student = Student.new(student_params)
if #student.save
redirect_to students_path
end
end
I recommend reading the documentation on Strong Parameters - to better understand how they work. https://github.com/rails/strong_parameters
You have to change
params.require[:students] to params.require(:students)
But this is still not good way to handle your params for create action, you should add private method student_params to your controller where you would whitelist your params. Like this:
def student_params
params.require(:student).permit(:first_name, :last_name)
end
Here you can find more about it,
http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

Rails: If my Quiz model should be created on completing the quiz, how does form_for know what to refer to?

I've been told that I should not create my Quiz object before my quiz is completed; A user could go to the quiz page, not complete it, and there would be an 'unused' quiz sitting on the database. I can see the logic of that.
I CAN'T see how my quiz is supposed to work without being passed a #quiz object. Here's my QuizzesController, which, when the quiz is needed, gets routed to the 'new' action:
class QuizzesController < ApplicationController
def index
end
def new
#user = current_user
#quiz = Quiz.create(user_id: current_user.id)
end
def create
#results = Quiz.where(user_id: current_user.id).last
redirect_to results_path
end
end
At the moment, you can see that I'm coding the actions as simply as possible. Later, in the 'new' action, I'll add a test to see if the current_user has done the quiz and, if so, redirect to results_path.
Here is my form partial which is rendered as part of quizzes/new.html.erb:
<%= form_for(#quiz) do |f| %>
<p>
<%= f.check_box(:answer1) %>
<%= f.check_box(:answer2) %>
<%= f.check_box(:answer3) %>
<%= f.check_box(:answer4) %>
<%= f.check_box(:answer5) %>
<%= f.check_box(:answer6) %>
<%= f.check_box(:answer7) %>
<%= f.check_box(:answer8) %>
</p>
<p>
<%= f.submit("Get my results!") %>
</p>
<% end %>
Once again, the quiz is very simple while I figure out what's going on.
But I'd like to know, if the #quiz object is not created in the 'new' action, what would I pass into form_for to build the form?
You can instantiate a Quiz object without saving it to the database:
def new
#user = current_user
#quiz = Quiz.new(user_id: current_user.id)
end
The generally used sequence of requests/actions is the following:
The new action just initializes the model's instance with default values, and renders the record with empty fields, usually in a edit view.
def new
#quiz = Quiz.new(user_id: current_user.id)
render :edit
end
create action create the record, and after the create action you should render either the view of the newly created record by redirection to show action with the same view, or to redirect to a new action, in case you are creating a sequence of the same instances of a model.
def create
#quiz = Quiz.create(params)
render :show # or redirect_to :new
end
edit action is to prepare edit fields, is it renders edit view with filled-in fields.
def edit
#quiz = Quiz.where(id: params[:id]).first
end
update action updates the record with values set in edit view, then it renders the show view on the current record.
def update
#quiz = Quiz.update(params)
render :show
end
show action just shows the model's found out with stored in the DB values, then it renders show view with filled-in fields.
def show
#quiz = Quiz.where(id: params[:id]).first
end
So in your show.erb view you get rendering the newly built, or found out instance of Quiz:
<%= form_for #quiz, url: {action: "create"} do |f| %>
<p>
<%= f.check_box(:answer1) %>
<%# ... %>
</p>
<p>
<%= f.submit "Create Quiz" %>
</p>
<% end %>
But I prefer simple-form gem:
<%= simple_form_for #quiz do |f| %>
<%= f.input :answer1, as: :boolean, checked_value: true, unchecked_value: false %>
<%= f.button :submit %>
<% end %>

Showing form error messages

I'm having trouble getting my redirect and error messages to work. From what I've read you cant get a forms errors to show up when you use redirect so I am trying to use render after it fails.
I have a new post form on a topic page. The url is "topic/1". If you make a post about the topic and something is wrong with the input I want it to go back to the page at topic/1 and display errors and I cant figure out how to get it to go back. Redirect (:back) does what I want but doesnt show the forms errors.
The form on the topic's show.html page:
<%= form_for(#post) do |f| %>
<%= render 'shared/post_error_messages' %>
<%= f.label :title, "Post Title" %>
<%= f.text_field :title %>
<%= f.label :content %>
<%= f.text_field :content %>
<%= f.hidden_field :parent_id, value: 0 %>
<%= f.hidden_field :topic_id, value: #topic.id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.submit "Create Post" , class: "btn btn-small btn-primary" %>
<% end %>
Create action in the Posts controller
def create
#post = Post.new(post_params)
#topic = Topic.find_by(id: params[:topic_id])
if #post.save
redirect_to #post
else
#topic = Topic.new
render "/topics/show"
end
end
I guess I'm mostly trying to do the render with the id from the page that the form was originally on.
Errors
The problem isn't anything to do with the way you're rendering the form (render or redirect) - it's to do with the way you're handling your ActiveRecord object.
When you use form_for, Rails will append any errors into the #active_record_object.errors method. This will allow you to call the following:
form_for error messages in Ruby on Rails
<%= form_for #object do |f| %>
<% #location.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
This only works if you correctly create your ActiveRecord object, which you seem to do
--
Nested
#config/routes.rb
resources :topics do
resources :posts, path: "", path_names: {new: ""}, except: [:index] #-> domain.com/topics/1
end
You'll be much better using the following setup for a nested route:
<%= form_for [#topic, #post] do |f| %>
...
<% end %>
This allows you to create a form which will route to the topics_posts_path, which is basically what you need. The controller will then balance that by using the following:
#app/controllers/topics_controller.rb
Class TopicsController < ApplicationController
def new
#topic = Topic.find params[:topic_id]
#post = Post.new
end
def create
#topic = Topic.find params[:topic_id]
#post = Post.new post_params
end
private
def post_params
params.require(:post).permit(:attributes)
end
end
You are overwriting the Topic you original found with a brand new, empty one - which shouldn't be necessary and which is causing the posts related to it to disappear.
Also - if your topic and post are related - you should create the post on the appropriate association #topic.posts instead of the main Post class.
The #topic.posts.new means that the post's topic-id is automatically updated with the value of the #topic.id ... which means you don't need to set it in the hidden-field on the form.
In fact it's better if you don't - just delete that hidden field entirely.
If you add that to the first time you get a new post too (eg in topics/show) then you won't need to pass in a value to the hidden-field.
Also I'd do the same for all the other hidden-fields on the server-side too. You don't really want the user to use firebug to hack the form and add some other user's id... so do it in the create action and don't bother with the hidden field
This should work:
def create
#topic = Topic.find_by(id: params[:topic_id])
#post = #topic.posts.new(post_params)
#post.user = current_user
#post.parent_id = 0
if #post.save
redirect_to #post
else
render "/topics/show"
end
end
if it doesn't - let me know what error messages you get (so we can debug)

Form resulting in blank post with no ID

I am new to Rails and working on creating a generic "facebook" type of app as practice with users and posts associated with each user. However, I'm currently having an issue where I think the form that I am using to create the posts is also being rendered out as a blank post with no post ID where I display all of the posts in a section below. I think that this post is being shown even before it is being saved to the database.
Here is my code in my view:
<div class="newpostcontainer">
<div class="newposttext">
<%= form_for([#user, #user.posts.build]) do |f| %>
<%= f.text_area :post, size: "69x1" %>
</div>
<div class="newpostsubmitbutton">
<%= f.submit %>
</div>
<% end %>
</div>
<% #user.posts.reverse_each do |p| %>
<div class="postedcontainer">
<div class="minipostpic">
<%= image_tag #user.photo.url, width: 32, height: 32 %>
</div>
<div class="nameofposter"><%= #user.name %></div>
<div class="dateofpost"><%= p.created_at%></div>
<div class="postcontent"><%= p.id%></div> <br>
<div class="postcontent"><%= p.post%></div> <br>
<div class="likecommentdelete">
<%= link_to "Delete", [p.user, p], method: :delete %> | Like | Comment
</div>
</div>
<%end%>
</div>
Here is my controller:
def index
#user = User.find(params[:user_id])
#posts = #user.posts.all
end
def create
#user = User.find(params[:user_id])
#post = #user.posts.create!(post_params)
redirect_to user_path(#user)
end
def show
#user = User.find(params[:user_id])
#post = #user.posts.find(params[:id])
redirect_to user_path(#user)
end
def destroy
#user = User.find(params[:user_id])
#post = #user.posts.find(params[:id])
#post.destroy
if #post.destroy
redirect_to user_path(#user)
else
redirect_to users_path
end
end
private
def post_params
params.require(:post).permit!
end
end
And here is my model:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
validates_presence_of :post
end
I'm pretty sure the issue has something to do with my form to create the new post because when I remove it or comment it out, the extra blank post with no post ID goes away.
Any thoughts or suggestions?
Thank you!!
I think you need to permit the field values to be posted:
i.e.,
params.require(:post).permit!
should be
params.require(:post).permit(:name, :post)
then only it will POST I think.
Hope it helps :)
This is because of rails 4 strong parameter feature. You need to whitelist your active models parameters. For more details refer to here.
In your case you need to do something like this:
params.require(:post).permit(:post)
where the ":post" inside require is your model and the other one is your permitted field that is your textarea.
Several issues -
Form
<%= form_for([#user, #user.posts.build]) do |f| %>
Why are you building an associative object? #user.posts.build will not persist your data, and will cause all sorts of non-conventional issues I would highly recommending building the posts associative object in your controller's new action before using in the view, so you can do this:
#app/controllers/users_controller.rb
def new
#user = current_user
#user.posts.build
end
<%= form_for #user do |f| %>
Association
You're trying to edit the post attribute with this statement:
<%= f.text_area :post, size: "69x1" %>
This won't work in any circumstance, as :post is an association, not an object. Rails only allows you to change / add attributes to specific objects, which means you'll be better doing something like this:
<%= f.fields_for :posts do |p| %>
<%= p.text_area :title %>
<%= p.text_area :body %>
<% end %>
Strong Params
You're currently permitting all your params? You'll be better doing this:
def post_params
params.require(:user).permit(posts_attributes: [:title, :body])
end
Use Posts Controller
A better way will be to just use the posts_controller, like this:
#app/controllers/posts_controller.rb
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
end
#app/views/posts/new.html.erb
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<% end %>

Redirect to show in another controller (Rails)

I have a form that allows the user to Post in the a group Show method. Upon posting, I want to redirect to the same page showing the new post. I'm using the following, but I get the error below. I'm not sure why #group is nil, because I've defined it in the show of my group controller.
No route matches {:id=>nil} missing required keys: [:id]
for
redirect_to group_path(#group)
<%=form_for([#post]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class = "field">
<%= f.label :event_name %>
<%= f.collection_select(:event_id, #events, :id, :title) %>
</div>
<div class = "field">
<%= f.text_area :comment, placeholder: "New Post..." %>
</div>
<%= f.hidden_field :user_id, value: current_user.id %>
<%=f.submit "Submit", class: "btn btn-large btn-primary" %>
<%end%>
class PostsController < ApplicationController
def create
if #post = Post.create(post_params)
flash[:success] = "Post Created!"
redirect_to group_path(#group)
else
redirect_to group_url
flash[:alert] = "Sorry - Post not created."
end
end
end
def show
#event = #group.events.build
#post = Post.new
#events = #group.events.includes(:posts)
#group = Group.find(params[:id])
end
In your create action you attempt to use the #group instance variable. You haven't defined it in the create action so you'll need to create it there if you want to use it. Since the call to create is in a separate request cycle the instance variables you defined in the show action are not available.
Update:
To get the group if you have an event_id and event belongs_to :group you would do:
event = Event.find(event_id)
#group = event.group
Set #group in create action. You have not assigned any value to #group there which is why you are getting error.
EDIT
As per your comment A Group has_many events so you can find the group as below:
#group = Event.find(params[:event_id]).group

Resources