Reputation: 453
I'm trying to add ajax to my comment form submission and I've run into an error when I'm trying to render a partial and I don't know how to solve it. I have everything set up properly and comments get created fine. But then I try to render the partial for the comments and I get this error:
undefined local variable or method `each' for #<#<Class:0xae4d760>:0xae59a78>
My create.js.erb
$("#comm_form_wrap").html("<%= escape_javascript(render :partial => "statuses/comment_form") %>");
$('#comment_box').val('');
$("#comments_wrap").html("<%= escape_javascript(render :partial => "statuses/comments") %>")
When I try to render statuses/comments
is causing the error.
Here's my partial:
<% @comments.each do |comment| %>
<div class="com_con">
<%= Rinku.auto_link(comment.content).html_safe %>
</div>
<% end %>
So then I tried passing the variables like this
$("#comments_wrap").html("<%= escape_javascript(render :partial => "statuses/comments", :locals => {:comment => comment}) %>")
but it gives this error
undefined local variable or method `each' for #<#<Class:0xae4d760>:0xae59a78>
Not sure what I'm missing here, I'm sure it's something small. Can anyone help me?
View
<% if member_signed_in? %>
<div id="comm_form_wrap">
<%= render "comment_form" %>
</div>
<div id="comments_wrap">
<%= render "comments" %>
</div>
<% end %>
**Edit**
comments_controller.rb
class CommentsController < ApplicationController
before_filter :authenticate_member!
before_filter :load_commentable
before_filter :find_member
def index
redirect_to root_path
end
def new
@comment = @commentable.comments.new
end
def create
@comment = @commentable.comments.new(params[:comment])
@comment.member = current_member
respond_to do |format|
if @comment.save
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back }
format.json
format.js
end
end
end
def destroy
@comment = Comment.find(params[:id])
respond_to do |format|
if @comment.member == current_member || @commentable.member == current_member
@comment.destroy
format.html { redirect_to :back }
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
end
end
end
private
def load_commentable
klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
@commentable = klass.find(params["#{klass.name.underscore}_id"])
end
def find_member
@member = Member.find_by_user_name(params[:user_name])
end
end
statuses_controller
def show
@status = Status.find(params[:id])
@commentable = @status
@comments = @commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
@comment = Comment.new
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
format.js
end
end
Logs
Processing by StatusesController#show as HTML
Parameters: {"id"=>"86"}
[1m[35mMember Load (1.0ms)[0m SELECT "members".* FROM "members" WHERE "members"."user_name" IS NULL LIMIT 1
[1m[36mStatus Load (0.0ms)[0m [1mSELECT "statuses".* FROM "statuses" WHERE "statuses"."id" = ? LIMIT 1[0m [["id", "86"]]
[1m[35mComment Load (2.0ms)[0m SELECT "comments".* FROM "comments" WHERE "comments"."commentable_id" = 86 AND "comments"."commentable_type" = 'Status' ORDER BY created_at desc LIMIT 15 OFFSET 0
[#<Comment id: 82, content: "and why not try again ha", commentable_id: 86, commentable_type: "Status", member_id: 1, created_at: "2014-06-26 06:27:05", updated_at: "2014-06-26 06:27:05">]
[1m[36mMember Load (1.0ms)[0m [1mSELECT "members".* FROM "members" WHERE "members"."id" = 1 LIMIT 1[0m
[1m[35mCACHE (0.0ms)[0m SELECT "members".* FROM "members" WHERE "members"."id" = 1 LIMIT 1
[1m[36m (0.0ms)[0m [1mSELECT COUNT(*) FROM "comments" WHERE "comments"."commentable_id" = 86 AND "comments"."commentable_type" = 'Status'[0m
Rendered statuses/_comment_form.html.erb (8.0ms)
[1m[35mCACHE (0.0ms)[0m SELECT "members".* FROM "members" WHERE "members"."id" = 1 LIMIT 1
Rendered statuses/_comments.html.erb (95.0ms)
Rendered statuses/show.html.erb within layouts/application (406.0ms)
Rendered layouts/_query.html.erb (108.0ms)
Rendered search/_search.html.erb (22.0ms)
Rendered layouts/_menu.html.erb (592.0ms)
Completed 200 OK in 2956ms (Views: 2312.1ms | ActiveRecord: 10.0ms | Solr: 0.0ms)
Upvotes: 1
Views: 3538
Reputation: 453
The answer above helped me solve this. Rendering the comments as a collection helped me render the partial through ajax and I also needed to define @comments
in my create
action in my comments_controller
as well to ensure it doesn't render blank.
Upvotes: 0
Reputation: 76784
Problem is your partial is calling @comments.each
:
<% @comments.each do |comment| %>
2 issues:
@comments
doesn't exist- Partials need to use
local
variables (they can't rely on@instance
vars)
--
Partials
You'll be best doing this:
<%= render partial"statuses/comments", collection: @comments, as: comment %>
There is a little-known piece of functionality in Rails' partials which allows you to basically "reload" the partial for each member of a collection.
The reason this is important is because it cuts out a LOT of code from your partial. If you use the partial I posted above, you'll only need this code inside the partial:
#app/views/statuses/_comments.html.erb
<div class="com_con">
<%= Rinku.auto_link(comment.content).html_safe %>
</div>
If you set the correct @instance variable
, and pass it into the collection
option of the partial
, Rails will basically reload the partial in a loop, like you have with the .each
loop now
This will also work for singular items:
<%= render partial: "statuses/comments", object: @comment, as: comment %>
--
Instance Variable
The second issue is the setting of your instance variable
In your controller, you are not setting the @comments
instance variable. This means you cannot load the contents of this variable into your view, consequently causing an issue like you've got
The way to fix this is very simple - use @instance variables
you have set in your controller!
--
Escape
You may also need to look at how to escape
quotes in your JS:
$("#comments_wrap").html("<%= escape_javascript(render :partial => \"statuses/comments\", :locals => {:comment => comment}) %>")
I'm not sure if this is applicable in this case, but I do know if you encapsulated quotes inside another set, you'll get errors from your JS
Upvotes: 3