Code reviews: my dumb use of acts_as_commentable (newbie)

With the help of several heroes here yesterday I beat my way into a
working solution to adding comments to one or more models in my
application using acts_as_comentable. Great plugin, but my
implementation is lame. I need enlightenment.

I have users who log in. For several views I want to let them add
comments. Enter act_as_commentable which does just this – it’s
polymorphic, so you just tell your model to act_as_commentable and it
obeys. However…

Say I have a model, view and controller of my reviews of movies, which
I’ll call Reviews. I write a reviews and I want to let my loyal users
add comments.

What does my view (rhtml) look like? The view shows my review, of
course, and perhaps a list of other users’ comments on that review.

But now, Joe wants to comment on my review. Here’s what I have done so
far:

(part of the rhtml of the view, displayed on “show_review” action)
… other stuff on my review, then the comment fields …

<% form_for :review, :url=> { :action => "save_comment" } do |f| %> Add Your Own Comment
  <%= f.hidden_field :review_id %>
  <p>
    <label for="title">Title</label>
    <%= f.text_field :new_comment_title, :size => 40 %>
  </p>

  <p>
    <label for="comment">Body</label>
    <%= f.text_field :new_comment_body, :size => 200 %>
  </p>

<%= submit_tag "Save Comment", :class => "submit" %>

<% end %>

My review.rb model has:
acts_as_commentable # yeah, this seems fine

attr_accessor :new_comment_title # do I really need this??
attr_accessor :new_comment_body # ditto
attr_accessor :review_id # c’mon, this can’t be necessary!

and my controller has
def show_review
@review = Review.find(params[:id]) # fine
@review.review_id = @review.id # Save for later, but … should
I?
end

def save_comment
@comment = Comment.new # fine, I guess.
@comment.title = params[:review][:new_comment_title] # seems
complicated
@comment.comment = params[:review][:new_comment_body] # ditto
@review = Review.find(params[:review][:survey_id]) # from saved
for later
@review.add_comment(@comment) # fine
redirect_to(:back)
end

Sure, it works, but there has to be a simpler way than defining
comment-specific variables in my model, and subsequent references in my
controller.

What say ye, oh gods of Rails? Striketh me down with thy wisdome and
simplicitie!

Tom “Dunce Boy”

Most of your questions will be answered by simply changing the way you
are saving comments. You need the review’s id in a hidden field so that
you can add the comment to the correct review, but try this:

@review = Review.find(params[:review_id]
@new_comment = @review.create_in_comments(params[:comment])

Change your comment fields to be named “comment[title]” and
“comment[comment]” so that you can just pass params[:comment]. The id
and type will be saved automatically. Since @new_comment will contain
the new comment, there is no need for the extra methods. Let me know if
you have more questions.

BTW, one good way to get an idea of the methods that any relationship
add to a model is to use script/console and look at the methods of an
instance of said model. For your review example, try this:

r = Review.find(:first)
puts r.methods.sort.join("\n")
puts r.methods.grep(/comment/).sort.join("\n")

The first call to methods will list all of the public methods available
to an instance of your Review class. The second will just show any
methods that have “comment” in their name. Then you can simply play
around with them in console or search a given api for more info on a
method. Hope I was of some help.

-Bill

One other thing I noticed. You should just use form_tag instead of
form_for :review. form_for is meant to create a form around a specific
object, and since your comment is not a review, form_tag would make more
sense.

<% form_tag :action => "save_comment" do %> Add Your Own Comment

<%= hidden_field_tag :review_id %>

Title <%= text_field_tag "comment[title]", :size => 40, :id => 'title' %>

Body <%= text_field_tag "comment[comment], :size => 200, :id => 'comment' %>

<%= submit_tag “Save Comment”, :class => “submit” %>
<% end %>

This should give you the jist of it. I have not tested this code, but it
should at least get you started.

Although, you could also use form_for :comment. In that case, you can
just name your fields :title, and :comment. Either way is fine. Note
that I added id’s to the tags because the default is to use the name as
the id and []'s are not allowed in id’s, only alphanumerics and _'s.

William –

Thanks, thank you, and thank you very much. Your responses all provided
exactly the kind of information I needed to help cure my ignorance. I
appreciate the time you took to read my post, and to answer in detail.
Some day when I get an actual clue, I’ll pass along the knowledge.
Until then, I am still

Tom (slightly enlightened) “Dunce Boy”

Ahh, don’t be so hard on yourself, everyone has been where you are. I
enjoy helping on this list and so do many others. This list truly has a
good group of people. Have fun and let me know if I can help with
anything else.

William P. wrote:

Ahh, don’t be so hard on yourself, everyone has been where you are. I
enjoy helping on this list and so do many others. This list truly has a
good group of people. Have fun and let me know if I can help with
anything else.

Can we use acts_as_commentable for different models in same app?

MaD wrote:

Can we use acts_as_commentable for different models in same app?
yes. i don’t see why not.

Thanks for replying.

Do you have some sample code?

I am bit confused,we are using comments for say blog and note in one app
so are they going to refer same table comment or what?

Can we use acts_as_commentable for different models in same app?
yes. i don’t see why not.