ActionController::UrlGenerationError in Comments#edit - Rails 4.0 - ruby-on-rails

I am using a ruby on rails blog tutorial and everytime I try to edit a comment I get an error.
Error: No route matches missing required keys: [:id].
Please help I am new to this.
Error found around line 3.
<h1>Editing comment</h1>
3. <%= form_for([:post, #comment]) do |f| %>
4. <div class="field">
5. <%= f.label :name %>
<%= f.text_field :name %>
Here is my routes.rb file code
Rails.application.routes.draw do
resources :posts do
resources :comments
end
end
My Comments_controller.rb code
class CommentsController < ApplicationController
# GET /comments
# GET /comments.json
def index
#comments = Comment.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #comments }
end
end
# GET /comments/1
# GET /comments/1.json
def show
#comment = Comment.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #comment }
end
end
# GET /comments/new
# GET /comments/new.json
def new
#comment = Comment.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #comment }
end
end
# GET /comments/1/edit
def edit
#comment = Comment.find(params[:id])
end
# POST /comments
# POST /comments.json
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #post, notice: 'Comment was successfully created.' }
format.json { render json: #post, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PUT /comments/1
# PUT /comments/1.json
def update
#comment = Comment.find(params[:id])
#post = #comment.post
respond_to do |format|
if #comment.update_attributes(params[:comment])
format.html { redirect_to #post, notice: 'Comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment = Comment.find(params[:id])
#post = Post.find(params[:post_id])
#comment.destroy
respond_to do |format|
format.html { redirect_to #post, notice: 'Comment was successfully deleted!' }
format.json { head :no_content }
end
end
def comment_params
params.require(:comment).permit(:post_id, :name, :email, :body)
end
end

So, to leave the comments alone, let me try to explain what I think it is your problem.
In your routes file you have nested resources, which means that this:
resources :posts do
resources :comments
end
end
are what is called nested resources, and this means that you have routes like:
posts/:post_id
posts/:post_id/comments/:comment_id
which you can see if you run rake routes.
This also means that the first route will call an action on your PostsController and the second route will call an action on your CommentsController.
So what I suggested you to do in your controller was to, first, render the form as [#post, #comment], which will tell the form_for helper to use your nested resource as the 'path to send the form'.
For this form to call your edit method you'll need to say that you want the form to be submitted there. This is done by the options for the form_for helper (http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html) and this is necessary because rails loves/is! RESTfull, and under this, the same route might have multiple behaviours depending on the HTTP verb/method you use.
So, have attention to this that I mentioned above, and you can probably guess what you are doing wrong.
As a last hint, your controller has this:
# GET /comments/1/edit
def edit
#comment = Comment.find(params[:id])
end
And this method renders this(I assume):
<h1>Editing comment</h1>
<%# I already fixed the form_for here %>
<%= form_for([#post, #comment]) do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
<% end %>
This form, since is rendered by the edit action, will (probably) be submitted to the update action. This update action is under /posts/:post_id/comments/:comment_id, and can be called using the PATCH(rails 4.0) verb. So your form_for needs, first, to have a post assigned to the variable #post, which should be passed by its controller. Second, it needs to go to the right route.
Here you are lucky since Rails is smart enough to see if what you're submitting is a new_record? and then its form_for will point to create or, if not, will point to update.
So all you need to do now, is to assign the right Post to #post and you are probably good to go.
Let me know if this worked for you.

Related

Item in Active Record not rendering correctly - Rails 4.2

Not quite sure if 'Active Record' is the right term. The DB? Postgres?
I'm following through Rails Tutorial and having a very frustrating issue. I've found quite a few posts on SO with people struggling, but majority of them went way off base for the answers, so I'm trying to find out what's wrong with my example.
My User Controller
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :email)
end
end
My User Model
class User < ApplicationRecord
has_many :micropost
validates :name, presence: true
validates :email, presence: true
end
My Microposts Model
class Micropost < ApplicationRecord
belongs_to :user
validates :content, length: { maximum: 140 },
presence: true
end
My Microposts Controller
class MicropostsController < ApplicationController
before_action :set_micropost, only: [:show, :edit, :update, :destroy]
# GET /microposts
# GET /microposts.json
def index
#microposts = Micropost.all
end
# GET /microposts/1
# GET /microposts/1.json
def show
end
# GET /microposts/new
def new
#micropost = Micropost.new
end
# GET /microposts/1/edit
def edit
end
# POST /microposts
# POST /microposts.json
def create
#micropost = Micropost.new(micropost_params)
respond_to do |format|
if #micropost.save
format.html { redirect_to #micropost, notice: 'Micropost was successfully created.' }
format.json { render :show, status: :created, location: #micropost }
else
format.html { render :new }
format.json { render json: #micropost.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /microposts/1
# PATCH/PUT /microposts/1.json
def update
respond_to do |format|
if #micropost.update(micropost_params)
format.html { redirect_to #micropost, notice: 'Micropost was successfully updated.' }
format.json { render :show, status: :ok, location: #micropost }
else
format.html { render :edit }
format.json { render json: #micropost.errors, status: :unprocessable_entity }
end
end
end
# DELETE /microposts/1
# DELETE /microposts/1.json
def destroy
#micropost.destroy
respond_to do |format|
format.html { redirect_to microposts_url, notice: 'Micropost was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_micropost
#micropost = Micropost.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def micropost_params
params.require(:micropost).permit(:content, :user_id)
end
end
My show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #user.name %>
</p>
<p>
<strong>Email:</strong>
<%= #user.email %>
<% if #user.micropost.any? %>
<%= #user.micropost.first %>
<% end %>
</p>
<%= link_to 'Edit', edit_user_path(#user) %> |
<%= link_to 'Back', users_path %>
When I load a Users page (6 or 7 in my case) I am seeing 'something' being outputted in this format, but it's showing
Which I feel like is an Active Record (?) index? I'm not sure how to get it to show the first (or any) Micropost of a User.
In some solutions I saw people used render #user.micropost but I get an issue about partials (Which I'm familiar with) but the tutorial says you should be able to use the syntax used previously (aka #user.email ) to solve it. So I feel I'm over complicating it?
My issue was I needed to use
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #user.name %>
</p>
<p>
<strong>Email:</strong>
<%= #user.email %>
<% if #user.micropost.any? %>
<%= #user.micropost.first.content %>
<% end %>
</p>
<%= link_to 'Edit', edit_user_path(#user)
%> |
<%= link_to 'Back', users_path %>
I should have realized when it was reporting a hash value.
you can't be rendering the show page because if you did you would get a no method or for nil class.
Your show action has no instance variable called #user.
For your show to display data you need a user object. In your case you have none.
So in your show method, add this:
#user.find_by(params[:id])
That will find the user 6 or 7 and allow you to call #
Can you paste the url from the browser so I can see where you actually are?

Cannot delete or update a parent row: a foreign key constraint fails - deleting a post in blog

I've checked out the other answers to similar questions and I think I understand what they are a saying but I'm at a loss to how to solve it.
I get this error message, when trying to delete a post in the blog on my site. I've tried from Rails console and get a similar message also.
ActiveRecord::StatementInvalid in PostsController#destroy
Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`mysite_development`.`comments`, CONSTRAINT `fk_rails_2fd19c0db7` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)): DELETE FROM `posts` WHERE `posts`.`id` = 3
posts_controller.rb
class PostsController < ApplicationController
before_filter :authenticate, :except => [ :index, :show ]
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:title, :body)
end
end
edit.html.erb
<h1>Editing Post</h1>
<%= render 'form' %>
<%= link_to 'Show', #post %> |
<%= link_to 'Back', posts_path %>
<%= link_to 'Delete', #post, method: :delete %>
_form.html.erb
<%= simple_form_for(#post) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :title %>
<%= f.input :body %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Any ideas?
It has nothing to do with your controller code. You added a database foreign constraing in your schema that disallows you to delete an object when there are associated records.
In this case, you are trying to delete an Post that has Comments attached. You need to alter the schema and update the foreign key definition to instruct the database what to do in this case. Specifically, you may probably want to delete the associated records on cascade.
In theory, you can use the dependent: :destroy Rails setting in the Post model to delete the Comments on cascade, but it's not a good idea as you have a foreign key in place. It will be faster and better if you delegate the task to the database in this case.
Try putting dependent: :destroy on the Model, which I imagine will be something like that. Luck.
class Post < ActiveRecord::Base
has_many :comments, dependent: :destroy
I only had enough time to do a quick skimming (so forgive me if I am overlooking things you may have already tried), though just noting to make sure that you clear/update fk's from all other tables linking to any values contained in the target table. There may be an automated way to do this rather than update every single table that uses a fk to that table, though in the meantime can be accomplish by simply clearing/updating those first, then executing the final update on the target table.

simple_form undefined method `model_name' for NilClass:Class

I'm learning Rails, and I would like to use simple_form.
I'm creating a simple app (my first one), and I want to create a signup form.
I used rails g scaffold User username:string password:string to create my model and controller.
I'm using Foundation gem too, if that's matter, and I install simple_form with the right command for Foundation.
I've been looking for answers for two hours, I tried many things, I have no idea of what's wrong with my code.
## app/views/home/index.html.erb ##
<%= simple_form_for #User do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<% end %>
## app/models/user.rb ##
class User < ActiveRecord::Base
end
## app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:username, :password)
end
end
I'm obviously doing something wrong, and I'm pretty sure I will feel like an idiot, but it's my first app :/
Thanks you.
EDIT: I forgot to say, I tried (desperately) every vars (#user, #users, #User, #Users), any of them doesn't works :/
Get rid of the form from the index.html.erb view (and no, don't put it in show.html.erb either!).
Place this form in the new.html.erb view:
<%= simple_form_for #user do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<%= f.submit %>
<% end %>
Note that the form should reference #user not #User.
Yep ... in the view you are using the #User instance variable (with uppercase U) but in the controller you assign the model to the #user instance variable (with lowecase u) :)
Put #user in lowcase (not #user)
<%= simple_form_for #user do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<% end %>
And save it as new.html.erb view not index.html.erb!

understanding of rails object life cycle issue

I am new to rails.I have some confusion about about rails object life cycle.In rails we have the bellow code.
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
then in the form we have
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
my confusion is in the new action in controller i have #user = User.new
and again in the create #user = User.new(params[:user]).
then in form i have <%= form_for(#user) do |f| %> .
My question is here at the form the #user object actually means waht?
I mean does this #user is going to hit the new action or create action.
If it is going to hit the create action then how this is happening because the form is actually comes from the new action so i can't figure it out how its hitting to the create action .
i know its very simple question.But i dont know how its happening as i am new to rails.
Please help me to make me understand the object flow.
thanks in advance.
The "new" action makes a new object and shows a form for editing it. That form submits to the "create" action because the object has not been saved yet.
If you did
form_for #user
and #user was a previously-saved object, the form would submit to the update action instead.
form_for is a bit magical, like a lot of rails: it does two things:
sets the "action" attribute of the form to point at either "/users" (for create) and "/users/:id" (for update)
in the case of update (ie for objects that already have an id) it also adds a hidden field which triggers the update action: this hidden field will look like this: <input type="hidden" value="put" name="_method">.
Have a look at form_for in your rails api.
It's hitting create action because of the proper form URL. When you run rake routes command, you'll see that POST /users leads to users#create action - and that's the URL in the new form. URL is set (and form fields are generated) properly by Rails because you pass User instance to the form.

Using <%= render comments %> always outputs an empty partial, even if there is nothing in the database

I'm starting to wonder if this is a bug with Rails 4, but I'm very new to rails and find myself smacking myself in the forehead eventually with most of the bugs I run in to. But I'm running into a wall on this one.
I have a Post. Posts have comments.
My Comment partial (/views/comments/_comment.html.erb)
<div class="comment-wrap">
<div class="row">
<div class="comment-meta">
<%= comment.commenter %>
<small><%= comment.created_at %></small>
<%= link_to 'Destroy', [comment.post, comment], method: :delete, confirm: 'Are you sure?', class: "tiny button radius right" %>
</div>
<div class="small-2 columns">
<img src="http://placehold.it/50" height="50" width="50" alt="Avatar Image"/>
</div>
<div class="small-10 columns">
<%= comment.body %>
</div>
</div>
</div>
Here is how I render that in .../views/posts/show.html.erb
<h4>Leave a comment</h4>
<%= render "comments/form" %>
<h4>Comments</h4>
<%= render #post.comments %>
Edit:Controller .../controllers/comments/comments_controller.rb
class CommentsController < ApplicationController
def create
#post = post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
redirect_to post_path(#post)
end
def destroy
#post = post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.destroy
redirect_to post_path(#post)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body, :post_id)
end
end
Edit: Posts Controller
class postsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:name, :description, :date, :address)
end
end
This will list out the comments, but the first item is always an empty partial, with the placeholder avatar and a delete button. I've checked in rails console to see how many comments a particular post has, just to make sure there wasn't some empty record in the db, but that's not the case. Why am I getting this empty and additional partial that does not match up with a database record?
It is because #post.comments.build in comments/form.html.erb. build() will always create a new empty object, and that comes before render(). Try replacing it with Comment.new so the empty comment won't be associated with the post.
The issue is that the form is above the <%= render #post.comments %> so there is an empty comment when you reach the partial for all the comments, even if there's none in database, put the <%= render "comments/form" %> below to fix this.

Resources