Reputation: 8503
I am having troubles with a polymorphic association in Rails. I have an application where it should be possible to comment on different models, such as Posts, Images, Projects
Right now I just have Posts to comment on. On the start page there is an index view of the latest Posts and each Post has a small Comment form underneath to comment on via Ajax, very much like Facebook.
My models look like this:
class Post < ActiveRecord::Base
belongs_to :post_category
belongs_to :user
has_many :comments, :as => :commentable
validates_presence_of :user_id
validates_presence_of :post_category_id
validates_presence_of :title
validates_presence_of :body
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
end
Now in my Comments controller I added the following method (I think I took it from railscasts or something), which I assume tries to find out the @commentable dynamically when creating an comment.
But this always returns the error undefined method
comments' for nil:NilClass`
# find commentable (parent) item
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value) unless name == 'user_id'
end
end
nil
end
def create
@commentable = find_commentable
@comment = @commentable.comments.build(params[:comment])
if @comment.save
redirect_to @comment, :notice => 'Comment was successfully created.'
redirect_to :id => nil
else
render :action => "new"
end
end
The two things I tried in my partial were:
leaving the commentable info out of the form
= form_for [@commentable, Comment.new], :remote => true do |f| #new_comment.add_comment = f.hidden_field :user_id, :value => current_user.id = f.text_field :content, :size => 55, :value => 'leave a comment...', :class => 'comment_form' = f.submit "send"
and 2. passing the commentable_id and commentable_type
= form_for [@commentable, Comment.new], :remote => true do |f|
#new_comment.add_comment
= f.hidden_field :user_id, :value => current_user.id
= f.hidden_field :commentable_id, :value => post_id
= f.hidden_field :commentable_type, :value => 'Post'
= f.text_field :content, :size => 55, :value => 'leave a comment...', :onfocus => 'this.select()', :class => 'comment_form'
= f.submit "send"
both without luck. Any help would be highly appreciated. the whole comments controller code is in this gist: https://gist.github.com/1334286
Upvotes: 2
Views: 1698
Reputation: 55263
Don't use @commentable
in the post show view, since it's only defined in the comments controller.
Do this instead:
_comment.html.erb: (the comment partial in the post show view)
<%= form_for ([comments, @vote]), remote: true do |f| %>
posts/posts_controller.rb:
<%= form_for ([@post, @vote]), remote: true do |f| %>
Upvotes: 0
Reputation: 6444
It seems like the commentable is not assigned correctly in the comments controller. This could have multiple reasons. Here is a setup that should work for you:
In the Posts controller, e.g. action "show":
@post = Post.find(params[:id])
In the posts/show view comments form:
= form_for [@post, @post.comments.new], :remote => true do |f|
You should be able to use your comments controller as it - but you should change the render
to e.g. a redirect_to :back
in the create action since the comments controller will most probably not have a "new" view on its own (it is dependent from the commentable)
Also, make sure that you have nested routes for all resources that can act as a commentable, like so:
resources :posts do
resources :comments do
end
resources :comments do
resources :comments # subomments
end
UPDATED to reflect information in the comments
Upvotes: 2