Couldn't find Comment without an ID - polymorphic associations - ruby-on-rails

The error appears when I try to submit a comment. - ActiveRecord::RecordNotFound in CommentsController#index - I followed this and this tutorial
the URL is:
.../articles/1/comments
comments_controller
class CommentsController < ApplicationController
before_action :set_comment
before_action :signed_in_user, only: [:new]
def index
#commentable = load_commentable
#comments = #commentable.comments
end
...
def create
#comment = #commentable.comments.new(comment_params)
#comment.user = current_user
if #comment.save
redirect_to #comment, notice: "Comment created."
else
render :new
end
end
....
private
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def set_comment
#comment = Comment.find(params[:id])
end
....
Full trace:

As per the stacktrace, error is appearing on set_comment method.
You must be having a callback before_action on set_comment which should not be there for index action. You should restrict that to only relevant actions.
For example:
before_action :set_comment, only: [:show, :edit, :update, :destroy]
So that this callback would only be invoked for show, edit, update and destroy actions.
UPDATE
Currently callback is set as before_action :set_comment without any restrictions so it will be invoked before each and every action. So, update it as suggested above.

Related

Why am I getting "AbstractController::DoubleRenderError" when calling redirect_to in after_action?

In the comments controller, I am redirecting to the articles show page after both create and destroy.
So I decided to write an after_action which would do the redirect_to.
class CommentsController < ApplicationController
before_action :find_article
before_action :find_comment, only: [:destroy]
after_action :goto_articles_page, only: [:create, :destroy]
def create
#comment = #article.comments.create(comment_params)
end
def destroy
#comment.destroy
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
def find_article
#article = Article.find(params[:article_id])
end
def find_comment
#comment = #article.comments.find(params[:id])
end
def goto_articles_page
redirect_to article_path(#article) and return
end
end
But this gives me AbstractController::DoubleRenderError after both create and destroy.
Why am I getting this error?
By default, Rails will render views that correspond to the controller action. See Rails Guides.
So in your create and destroy actions, Rails is performing a render by default. Then your after_action (which happens after the action) is redirecting, so it's double rendering.
Instead of an after_action, you could call the goto_articles_page method in your controller actions.
For example:
def destroy
#comment.destroy
goto_articles_page
end
def goto_articles_page
redirect_to article_path(#article) #return not needed
end
I think using return when rendering any action but when redirect_to use then not need to use return then finally you can remove and return
Rails guide very nicely explained that you can follow this carefully
redirect_to explanation
Hope to help

How to fix nil:NilClass error in polymorphic-associations?

This is my comment controller code
private
def set_commentable
#commentable = Question.find(params[:question_id])
#commentable = Comment.find(params[:comment_id])
end
I've tried but i'm getting below error, I hope I did error in passing of comment id
undefined method `set_comment' for #<CommentsController:0xb34e3348>
Add this in your comments controller
def set_comment
#comment = Comment.find(params[:id])
end
Since you don't have set_commentable inside your CommentsController your are getting undefined method error:
before_action :set_comment, only: [:show, :edit, :update, :destroy, :create]
private
def set_comment
#commentable = Comment.find(params[:id])
end

Implementing most recent post in my index.html.erb Rails template

I've been putting the finishing touches on my app all day with the help of some useful answers here and would like to know how this feature can be executed. I have an idea set up in my post_controller file where I want to show the top 10 most recent posts created based on the date that they were created. I also plan on doing this for my comments as well laster on. I am showing all users post in the views/post/index.html.erb file. I wrote this line of code in the posts_controller: posts = Post.order('created_at DESC').limit(10). I've searched here thoroughly but don't understand how some other users got this to work, any insight? Thanks in advance.
posts_controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :vote]
before_action :require_user, only: [:new, :create, :edit, :update, :vote]
before_action :require_creator, only:[:edit, :update]
def index
posts = Post.order('created_at DESC').limit(10)
#posts = Post.all.page(params[:page]).per_page(10)
end
def show
#comment = Comment.new
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.creator = current_user
if #post.save
flash[:notice] = "You created a post!"
redirect_to posts_path
else
render :new
end
end
def edit
end
def update
#post = Post.find(params[:id])
if #post.update(post_params)
flash[:notice] = "You updated the post!"
redirect_to post_path(#post)
else
render :edit
end
end
def vote
Vote.create(voteable: #post, creator: current_user, vote: params[:vote])
respond_to do |format|
format.js { render :vote } # Renders views/posts/vote.js.erb
end
end
private
def post_params
params.require(:post).permit(:url, :title, :description)
end
def set_post
#post = Post.find(params[:id])
end
def require_creator
access_denied if #post.creator != current_user
end
end
The posts variable you've declared in your index action will not be available in your view. What you need to do is update the line where you're retrieving the posts using instance variable as follows:
def index
#posts = Post.page(params[:page]).order('created_at DESC').per_page(10)
end

“Couldn't find [model] without an ID” Rails 3.2.3

For some reason, I keep getting this error.
Couldn't find Album without an ID
But that doesn't make sense because in my debug.params it says:
{"utf8"=>"✓",
"authenticity_token"=>"os9DVVZS6//bs3Ne2Xfrh4VnKXNtDXkZaE4s/3iQagE=",
"video"=>{"url"=>"www.youtube.com/watch?v=yIRuri1AB0I",
"album_id"=>"1"},
"commit"=>"Next"}
Here is the controller:
class VideosController < ApplicationController
include AlbumsHelper
before_filter :signed_in_user, only: [:create, :destroy] #add update later
before_filter :correct_user, only: :destroy
def show
#video = Video.find(params[:id])
end
def new
if signed_in?
#album = Album.find(params[:album_id])
#video = #album.build_video
end
end
def create
#album = Album.find(params[:album_id])
#video = #album.build_video(params[:video])
if #video.save
flash[:success] = "Success!"
redirect_to new_small_reward_path(:album_id => #album)
else
render 'new'
end
end
end
I even added a hidden field to the form, which I didn't think I should have to do, but decided to try:
The URL says /videos/new?album_id=1 before you click submit.
This problem completely goes away if I write the controller with this:
def new
##album = Album.find(params[:album_id])
end
and then continue to use the class variable throughout the entire thing. But someone told me that using a class variable is discouraged. How do I do this correctly?
#album = Album.find(params[:video][:album_id])

refactoring generated action code in the controller

If I generate a scaffold I get the standard actions index, new, show, create .... all of which contain a line e.g. like
#comment = Comment.find(params[:id])
Does it make sense to put this line in a seperate method into the controller like
def load
#comment = Comment.find(params[:id])
end
Is this an advantage? Thx for your time
Yes to the separate method, and also yes to using a before_filter.
class CommentsController < ApplicationController
# Whitelist your before_filter like this. Or you can blacklist it with :except => []
before_filter :load_comment, :only => [:edit, :update, :destroy, :show]
def show
end
def index
#comments = Comment.all
end
def new
#comment = Comment.new
end
# etc ...
protected
def load_comment
#comment = Comment.find(params[:id])
end
end

Resources