Trying to look up comment through an ID, but failing

I am trying to allow users to reply through comments by allowing users
to click a reply link next to the parent comment. It will send in a
parameter to the ‘new’ comment view, like so:

| <%= link_to “Reply”, new_comment_path(:in_reply_to => comment.id) %>

The form will use the :in_reply_to parameter in order to save that id as
the parent id, like so:

comments_controller#new:
@comment_parent = Comment.find(params[:in_reply_to])

comments_form view:
<%= form_for([@comment]) do |f| %>
<%#= render ‘shared/error_messages’, :object => f.object %>


<%= f.label :title %>

<%= f.text_field :title %>


<%= f.label :content %>

<%= f.text_area :content %>

<%= f.hidden_field :parent_id, :value => @comment_parent.id %>

<%= f.submit “Post Comment” %>

<% end %>

So, in the create controller, I want to create a new comment based on
the parameters, and then find the parent comment by looking up the
parent_id in Comment.find, but it cannot find any comment with that ID.

comments_controller#create
@comment = Comment.new(params[:comment])
@comment.user_id = current_user.id
@comment.save!
@comment_parent = Comment.find(params[:parent_id]) # cannot find a
comment with this ID?
@comment_parent.children << @comment
if @comment.save
flash[:success] = “Comment saved.”
@comment_parent.save
redirect_to @comment
else
flash[:error] = “Error in creating comment.”

@comments = @commentable.comments.paginate(:page =>

params[:page])
render ‘new’

I get this error: Couldn’t find Comment without an ID, from this line:
@comment_parent = Comment.find(params[:parent_id])

I also try @comment_parent = Comment.find(@comment.parent_id), but I get
the same error.

Thank you.

Kelp K. wrote:

comments_controller#new:
@comment_parent = Comment.find(params[:in_reply_to])

Why not just:
@comment = Comment.new
@comment.parent_id = params[:in_reply_to] if params[:in_reply_to]

</div>
  <%= f.hidden_field :parent_id, :value => @comment_parent.id %>

and skip the :value assignment in the view, the value is already there

and you shouldn’t need any of this…

  @comment_parent = Comment.find(params[:parent_id])
  @comment_parent.children << @comment

Unless a day spent in WCF has corrupted my brain too much…

place a hidden field in the form, add link_to_function and change the
value
of the hidden field with javascript.

In the controller if the value of the hidden fill is empty the comment
has
no parent, else it does.

example with jquery

$("#the_form [type=hidden]").val("<%=comment.id%>")

this will put the id value of the selected comment in the form parent
hidden
field

Nice, is there a way that I can save the particular page from which the
user is replying to, so I can redirect him there afterwards?

In my show controller for my comments, I have this:
@commentable = find_commentable
where commentable can be article, profile, etc.

Would I do the exact same thing to pass it all throughout the comment
posting process, or is there a more efficient way to do this?

just put

redirect_to :back

at the end of the create

oh , i forgot you are doing polymorphic associations sorry,

redirect_to polymorphic_path(@commentable)

remember to catch @commentable with the find_commentable method

you can find it iterating the params hash or user a context_Type in the
route , i like that last one more.

radhames brito wrote:

just put

redirect_to :back

at the end of the create

Hi,
When I try that with a threaded comment, it runs into an error:
Cannot redirect to nil!

I am using a polymorphic association for my articles,profiles and
comments. My comments controller marks the articles and profiles as
commentable, but I have to take a different approach when it comes to my
comments.

radhames brito wrote:

oh , i forgot you are doing polymorphic associations sorry,

redirect_to polymorphic_path(@commentable)

remember to catch @commentable with the find_commentable method

you can find it iterating the params hash or user a context_Type in the
route , i like that last one more.

Do you know if there is anyway for my find_commentable method to treat a
comment the same way as an article?

So, when a user tries to reply to a comment, the URL looks like this:
http://localhost:3000/comments/new?in_reply_to=56

When a user replies to an article (or profile), it looks like this:
http://localhost:3000/articles/304

The find_commentable way only works for the second method URL, since it
cannot find a commentable in the first one.

Sorry, this is my first Rails application, so my code is very cluttered,
and I don’t think I thought everything through the first time.

Here’s my comments controller:

On Fri, Sep 17, 2010 at 7:57 PM, Kelp K. [email protected] wrote:

route , i like that last one more.

Do you know if there is anyway for my find_commentable method to treat a
comment the same way as an article?

So, when a user tries to reply to a comment, the URL looks like this:
http://localhost:3000/comments/new?in_reply_to=56

for this you will need to create another controller otherwise it will get
messy
and you will have to catch the owner of the first comment. One thing you
should understand is that
you keep trying to treat comments as if they were not associated and as
if
they were, let me explain.

comments belong to commentable, and you created this route

articles :has_many :comments

this route is nesting commentes like this

/articles/1/comments

this is to help you get the parent of the comment, the params hash will
catch that id after the articles and create a key called
articles_id, take a look at the find_commentable function

def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nilend

For each value in the params hash,( note that the params hash has this
format, :id=>“1”, this is , name=>value), it uses a regular
expression to see if the name ends with _id, hoping that only the
commentable object will end like this i then takes the first part of
the name( thats what $1 does if there are more (.+) in the regular
expresion you refer to them in order, $2 , $3 etc), in case of
article_id it
will take article , then with constantize it becomes Article and a find
is
perform passing as an id the value corresponding to
article_id, so it return the instance that has those comments as childs.

now lets say you try to do this without

articles :has_many :comments

you have to provide the parent object somehow , if you access
http://localhost:3000/comments/new?in_reply_to=56
who does that object belongs to really when you access
/articles/1/comments,
active record will see that the comments created
that way have no commetable_type and no commetable_id, those are the 2
fields AR uses for the polymorphic associations.

What you are trying yo do is easy, but is not the rigth way , you have
to
have comments belong to commentable and to themself
then on the commetable show iterate the comments that have no parent .
inside the iteration iterate for their children.

radhames brito wrote:

On Fri, Sep 17, 2010 at 7:57 PM, Kelp K. [email protected] wrote:

What you are trying yo do is easy, but is not the rigth way , you have
to
have comments belong to commentable and to themself

belongs_to :commentable, :polymorphic => true
has_many :comments, :dependent => :destroy, :as => :commentable

Is this fine inside of my comment.rb model?

then on the commetable show iterate the comments that have no parent .
inside the iteration iterate for their children.

What does this accomplish? I find the comments that have children, but
what for?

by parent i mean commets where the parent_id is nil, not comments wherre
comentable is nil,

Comment.rb is ok but you still need to self refer, to create the
threads.

ill tell you what. i will make this tomorrow and send it to you ill try
to
commented well, do you want it in rails 2 or 3?

is the comment form in the commentable show view , for example,
comments
are displayed at the bottom of the the article, and is the same with any
commentable, you dont need this

def new
@commentable = find_commentable <===== is no needed
here
@comment = Comment.new <====== this is ok
@comment.parent_id = params[:in_reply_to] if
params[:in_reply_to] <==== where is params[:in_reply_to]
coming
from?
end

since the user will never go there, that is the new view .

def create
@commentable = find_commentable <=== as explained
returns
@article or whatever from the /article/1 path
if @commentable.nil? # Threaded Comments <==== this will
never
happen under normal circumstances
@comment = Comment.new(params[:comment]) <==== you are
creating
orphan comments and will never be able to read them
else
@comment = @commentable.comments.build(params[:comment])
<
===== this is ok
end
@comment.user_id = current_user.id
<=========== this is ok , from here to the end of create
if @comment.save
flash[:success] = “Comment saved.”
redirect_to polymorphic_path(@commentable)
else
flash[:error] = “Error in creating comment.”

@comments = @commentable.comments.paginate(:page => params[:page])

  render 'new'
end

end

now the destroy action

def destroy
@commentable = find_commentable <== no
need to find the parent you are going to delete it
if @commentable.comments.find(params[:id]).destroy <== no ,
change this to @comment = Comment.find(params[:id])
flash[:success] = “Comment
deleted.”
else
flash[:error] = “Comment could not be deleted.”
end
redirect_to @commentable
end

change the above to

def destroy
@comment = Comment.find(params[:id])
if @comment.destroy
flash[:success] = “Comment
deleted.”
else
flash[:error] = “Comment could not be deleted.”
end
redirect_to @commentable
end

the edit

def edit
@commentable = find_commentable
@comment = @commentable.comments.find(params[:id])
@title = “Edit Comment”

The following code allows editing directly on the article page.

@comments = @article.comments.paginate(:page => params[:page])

render ‘articles/show’

end

same as the new , is you are editing at he show of the comentable the
user
will never go to the comments edit page.

now the update

def update
@commentable = find_commentable
@comment = @commentable.comments.find(params[:id])
if @comment.update_attributes(params[:comment])
flash[:success] = “Updated Comment”
redirect_to @commentable
else
flash[:error] = “Comment update failed.”
@comments = @commentable.comments.paginate(:page => params[:page])
render ‘edit’
end
end

this one is ok but pay attention to render ‘edit’, if the user will
never
go there.

and last

def correct_user
@commentable = find_commentable
redirect_to(@commentable) unless current_user.admin?
end

try using an authorization gem instead

ill try to have it ready by tomorrow what is going to delay me is that i
will try to comment everything so that you can understand.

it will be simple just to demonstrate how to create threaded comments,
one
articles model and one proyects model, comments will belong to both, and
will be threaded.

ill will throw in some ajax for your liking

radhames brito wrote:

is the comment form in the commentable show view , for example,
comments
are displayed at the bottom of the the article, and is the same with any
commentable, you dont need this

Yes, right now. The article show page renders a partial of a comment
form.

def new
@commentable = find_commentable <===== is no needed
here
@comment = Comment.new <====== this is ok
@comment.parent_id = params[:in_reply_to] if
params[:in_reply_to] <==== where is params[:in_reply_to]
coming
from?
end

My article’s show page renders a partial for comments:
<%= render ‘shared/comments’ %>

Here is what the comments looks like:
<% unless @comments.nil? || @comments.empty? %>
<%= render :partial => ‘shared/comment’, :collection => @comments %>
<%#= will_paginate @comments %>
<% end %>

And each comment has this link which is where the params[:in_reply_to]
comes from:
| <%= link_to “Reply”, new_comment_path(:in_reply_to => comment.id) %>

def create
@commentable = find_commentable <=== as explained
returns
@article or whatever from the /article/1 path
if @commentable.nil? # Threaded Comments <==== this will
never
happen under normal circumstances
@comment = Comment.new(params[:comment]) <==== you are
creating
orphan comments and will never be able to read them
else
@comment = @commentable.comments.build(params[:comment])
<
===== this is ok
end
@comment.user_id = current_user.id
<=========== this is ok , from here to the end of create
if @comment.save
flash[:success] = “Comment saved.”
redirect_to polymorphic_path(@commentable)
else
flash[:error] = “Error in creating comment.”

@comments = @commentable.comments.paginate(:page => params[:page])

  render 'new'
end

end

now the destroy action

def destroy
@commentable = find_commentable <== no
need to find the parent you are going to delete it
if @commentable.comments.find(params[:id]).destroy <== no ,
change this to @comment = Comment.find(params[:id])
flash[:success] = “Comment
deleted.”
else
flash[:error] = “Comment could not be deleted.”
end
redirect_to @commentable
end

change the above to

def destroy
@comment = Comment.find(params[:id])
if @comment.destroy
flash[:success] = “Comment
deleted.”
else
flash[:error] = “Comment could not be deleted.”
end
redirect_to @commentable
end

the edit

def edit
@commentable = find_commentable
@comment = @commentable.comments.find(params[:id])
@title = “Edit Comment”

The following code allows editing directly on the article page.

@comments = @article.comments.paginate(:page => params[:page])

render ‘articles/show’

end

same as the new , is you are editing at he show of the comentable the
user
will never go to the comments edit page.

now the update

def update
@commentable = find_commentable
@comment = @commentable.comments.find(params[:id])
if @comment.update_attributes(params[:comment])
flash[:success] = “Updated Comment”
redirect_to @commentable
else
flash[:error] = “Comment update failed.”
@comments = @commentable.comments.paginate(:page => params[:page])
render ‘edit’
end
end

this one is ok but pay attention to render ‘edit’, if the user will
never
go there.

and last

def correct_user
@commentable = find_commentable
redirect_to(@commentable) unless current_user.admin?
end

try using an authorization gem instead

Sorry about the edit and destroy methods. You can ignore them for now. I
was going to change them after I learned how the create and new methods
worked. Don’t worry about the edit and destroy methods.

I am using Rails 3.

ok its done , tomorrow ill add ajax and the comments

can you give me your email to send you the proyect?

i dont have and about at github yet

try this?
def create

redirect_to request.env[‘HTTP_REFERER’]

he is testing and some times is [‘HTTP_REFERER’] empty that why he gets
an
error with :back

In the readme i explain a bit of where im at with this , i think is ok
for
now but i will add comments to the code

radhames brito wrote:

GitHub - rbritom/Simple_polymorphic_nested_comments: Polymorphic comments that can have nested replies

In the readme i explain a bit of where im at with this , i think is ok
for
now but i will add comments to the code

Wow, thank you so much for spending your time to do this.

hum ? i didnt see any more replays from you so i stopped adding features
to
it. I was going to add the ajax and the rest of the comment right away ,
it
was just last night that i thought maybe it was because you where
replaying
from your job and that during the weekend you could not reply that i
havent
heard anything from you. If you are still interest ill will finish right
away and add the ajax and the rest of the comment.