this is my index/post for rendering a comment
<% #posts = Post.where(user_id: current_user.all_user_ids).order("created_at desc") %>
<%#posts.each do |post| %>
<div id="comment-action">
<button id="<%= "#{post.id}" %>"> View comment</button>
<%= link_to "View Comments", "#post_comments_#{post.id}" %>
<section class="comments-section" id="post_comments_<%= post.id %>" >
<br>
<div id="comments">
<%= render 'commenters/newsfeedcomment', obj: post %>
</div>
<% if current_user == post.user %>
<h6 align="right"><%= link_to 'Edit', edit_post_path(post) %></h6>
<h6 align="right"><%= link_to 'Delete', { :id => post ,:controller => 'posts',:action => 'destroy'} %></h6>
<% end %>
</section>
</div>
<% end %>
now i past a object to my _newsfeedcomment which is obj: post
heres my newsfeedcomment
<% obj.commenters.each do |c| %>
<li class = 'comments'>
<br><%= image_tag c.user.profile.avatar.url, size:"50x50" %>
<a href="<%= "#{profile_path(c.user.profile)}" %>">
<%= c.user.profile.firstname + " " + c.user.profile.lastname %></a> : <%= c.comment %>
<br><%= time_ago_in_words(c.created_at) %> ago
</li>
<% if current_user == c.user %>
<%= link_to "Delete comment", [c.post, c], method: :delete %>
<%= link_to "Edit comment", edit_post_commenter_path(c.post, c) %>
<% end %>
<% end %>
and i want to render my newsfeedcomment again for my ajax
$('#comments').append("<%= j render(:partial => 'commenters/nesfeedcomment', obj: post) %>");
and this is my error
undefined local variable or method `post' for #<#:0x007f8660e313e8>
i guess rails cant read my object? is there any approach so i can finish my project please someone help me...
heres my controller
def create
#comment = #post.commenters.create(params[:commenter].permit(:comment))
#comment.user_id = current_user.id
#comment.save
if #comment.save
respond_to do |format|
format.html {redirect_to posts_path}
format.js
end
else
redirect_to posts_path
end
end
<%= render 'commenters/newsfeedcomment', obj: post %>
This code works in index.html because post is just the looped object from #posts
UPDATE:
Thanks for updating with your controller.
What you'll want to do is to provide a .js format response to your comments_controller's create action.
This can be done by providing a rendered view as app/views/comments/create.js.erb
In the create.js.erb, just have:
$('#comments').append("<%= j render(:partial => 'commenters/nesfeedcomment', obj: #post) %>");
or
$('#comments').append("<%= j render(:partial => 'commenters/nesfeedcomment', obj: #comment.post) %>");
And that is it.
What you were missing is simply the definition of post in your block, because it was not assigned as a variable, and ruby is interpreting it as a call for some method post - hence your error message: undefined local variable or method 'post'.
i create another render file just like newsfeedcomment
commenters/commentlist.html.erb
<li class = 'comments'>
<br><%= image_tag #comment.user.profile.avatar.url, size:"50x50" %>
<a href="<%= "#{profile_path(#comment.user.profile)}" %>">
<%= #comment.user.profile.firstname + " " + #comment.user.profile.lastname %></a> : <%= #comment.comment %>
<br><%= time_ago_in_words(#comment.created_at) %> ago
<% if current_user == #comment.user %>
<%= link_to "Delete comment", [#comment.post, #comment], method: :delete %>
<%= link_to "Edit comment", edit_post_commenter_path(#comment.post, #comment) %>
<% end %>
</li>
and this is my create.js.erb
var content = "<%= j render(:partial => 'commenters/commentlist', obj: #comment) %>";
var $post = $("#post_comments_<%= #comment.post_id %>");
var $last_comment = $post.find('#comments > li:last');
if ($last_comment.length > 0) {
$last_comment.after(content);
} else {
var $comments = $post.find('#comments');
$comments.prepend(content)
}
Related
Want to add a comment feature with ajax in Rails. I can't fetch comments after posting automatically. It's not working.
An error:
ActionView::Template::Error (undefined method `each' for nil:NilClass):
controllers/posts_controller.rb
class PostsController < ApplicationController
def create
#post = Post.new(create_params)
if #post.save
render :index
end
end
private
def create_params
params.require(:post).permit(:content)
end
end
controllers/home_controller.rb
class HomeController < ApplicationController
def index
#post = Post.new
#posts = Post.all
end
end
views/home/index.html.erb
<div id="postForm">
<%= render partial: 'posts/form', locals: { post: #post } %>
</div>
<div class="postContainer" id="postArea">
<ul>
<%= render partial: 'posts/index', locals: { posts: #posts } %>
</ul>
</div>
views/posts/index.js.erb
$("#postArea").html("<%= j(render 'index', { posts: #posts }) %>")
$("textarea").val('')
views/posts/_index.html.erb
<ul>
<% posts.each do |post| %>
<li><%= post.content %></li>
<% end %>
</ul>
views/posts/_form.html.erb
<%= form_with(model: post, url: posts_path) do |f| %>
<form>
<div class="form-group">
<label for="contents">Content</label>
<%= f.text_area :content, class: "form-control", rows: "2" %>
</div>
<div>
<%= f.submit "Submit", type: "submit", class: "btn btn-primary" %>
</div>
<% end %>
I have fixed it done.
controllers/posts_controller.rb
def create
#post = Post.new(create_params)
if #post.save
render :index
end
end
views/posts/_index.html.erb
<ul>
<% #posts.each do |post| %>
<li><%= post.content %></li>
<% end %>
</ul>
I have implemented a favorites system into my rails app, which works on the individual show page for the Tracks model. This is all handled through the Favorites controller, so I am attempting to use the same js file for both index and show pages. This is what I have tried so far. It works if I only have the show page material, the javascript doesn't work at all for either if I do it this way.
favorite.js.erb
<% if current_page?(track_path(#track)) %>
$("#favorites").html("<%= escape_javascript(render('tracks/favorites')) %>");
<% else %>
$("#favorites").html("<%= escape_javascript(render('albums/favorites')) %>");
<% end %>
the partial for tracks/favorites
<% if user_signed_in? && current_user.favorited?(#track) %>
<%= link_to image_tag('icons/heart_full.svg', width: 20), track_unfavorite_path(#track), method: :post, remote: true %>
<% else %>
<%= link_to image_tag('icons/heart_empty.svg', width: 20), track_favorite_path(#track), method: :post, remote: true %>
<% end %>
the partial for albums/favorites
<% if user_signed_in? && current_user.favorited?(track) %>
<%= link_to image_tag('icons/heart_full.svg', width: 20), track_unfavorite_path(track),
method: :post, remote: true %> <%= pluralize( track.favorites.count, 'favorite' ) %>
<% else %>
<%= link_to image_tag('icons/heart_empty.svg', width: 20), track_favorite_path(track),
method: :post, remote: true %> <%= pluralize( track.favorites.count, 'favorite' ) %>
<% end %>
Passing the instance variable as the parameter works for the show page, but trying to do it for the loop results is what is confusing me.
favorites_controller.rb
class FavoritesController < ApplicationController
before_action :authenticate_user!
before_action :find_track
def favorite
#track.favorites.where(user_id: current_user.id).first_or_create
respond_to do |format|
format.html { redirect_to #track }
format.js
end
end
def unfavorite
#track.favorites.where(user_id: current_user.id).destroy_all
respond_to do |format|
format.html { redirect_to #track }
format.js
end
end
private
def find_track
#track = Track.find(params[:track_id])
end
end
The view for Track show page is simple:
<div id="favorites">
<%= render 'tracks/favorites' %>
</div>
The view for the loop on the index page:
<% #tracks.each do |track| %>
<div class="track_thumbnail">
<% if track.avatar? %>
<%= link_to image_tag(track.avatar.url), track_path(track), width: 100, title: track.title %>
<% else %>
<%= link_to image_tag(track.user.avatar.url), track_path(track), width: 100, title: track.title %>
<% end %>
<%= link_to track.user.username, user_path(track.user) %>
</div>
<div class="track_overview">
<h2><%= link_to track.title, track_path(track) %><% if track.explicit == "explicit" %> (explicit)<% end %></h2>
<p class="description"><%= truncate(track.description, length: 160) %></p>
<div class="icons_container">
<div id="favorites">
<%= render 'albums/favorites', :track => track %>
</div>
</div>
</div>
<% end %>
I am trying to use AJAX functionality in order to create a new Task in a simple ToDo list application.
Currently the list is set up like this:
<h2> TO DO </h2>
<div class="wrapper">
<ul id="incomplete">
<% #task.each do |f| %>
<% if f.complete == false %>
<div id="<%= f.id %>">
<p class= "title"><%= f.title %></p>
<%= form_for f, remote: true do |task| %>
<%= task.check_box :complete, class: "check_box" %>
<%= task.submit %>
<% end %>
</div>
<% end %>
<% end %>
</ul>
</div>
<h2> COMPLETED </h2>
<div class="wrapper">
<ul id="completed">
<% #task.each do |f| %>
<% if f.complete == true %>
<div id="<%= f.id %>">
<p class="title"><%= f.title %></p>
<%= form_for f, remote: true do |task| %>
<%= task.check_box :complete, class: "check_box" %>
<%= task.submit %>
<% end %>
</div>
<% end %>
<% end %>
</ul>
</div>
<p id="new_link"><%= link_to "New Task", new_task_path, remote: true %></p>
<div id="new_task">
</div>
When the "New Task" link is pressed, it executes a js file which loads the following partial:
<%= form_for #task, remote: true do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.submit "Create" %>
<% end %>
My create method is below:
def create
#task = Task.new(task_params)
#task.save
respond_to do |format|
format.html
format.js
end
end
When I remove the "remote: true" from my partial form, page resets and the new task appears in the new , however, when I do use the "remote: true", and execute my create.js.erb file, nothing is changed in the DOM. Here is my create.js.erb file:
$('#incomplete').append($("#<%= #task.id %>"));
console.log("<%= #task.title %> has been saved.");
I'm not receiving any errors in my consoles, and the console.log line on the create.js.erb logs to the console without a problem the task title and the rest of the string.
I'm pretty lost in why the create.js.erb file is not manipulating the DOM. This code provides no response visually, only the post to the console.
I am try to render my comments with ajax in my rails app...but it is not working and the comments diplay just after I redirect the page...so the comment get created successfully but the problem is rendering comments with ajax and jquery!!!!
I have this lines in my application.html.erb:
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
and this require line in my application.js:
//= require jquery
//= require jquery_ujs
here is my show.html.erb file under posts :
<div id="posts" class="transitions-enabled">
<div class="box panel panel-default">
<%= render 'post', post: #post %>
</div>
</div>
my _post partial:
<div class="panel-body">
<%= link_to image_tag(post.user.avatar.url, size: "50x50", class: "img-circle"), profile_path(post.user.user_name) %>
<ul class="posts-shows">
<li><strong><%= link_to post.user.user_name, profile_path(post.user.user_name) %></strong></li>
<li><small><%= link_to "#{time_ago_in_words(post.created_at)} ago", post_path(post), class: "time-link" %></small></li>
</ul>
<p class="disc-posts"><%= post.description %></p>
<%= link_to image_tag(post.image.url(:large), class: "img-responsive img-in" ) %><br/>
<% if post.user == current_user %>
<div><%= link_to "Edit", edit_post_path(post) %> | <%= link_to "delete", post, method: :delete, data: {confirm: "Are you sure?"} %> </div>
<% else %>
<div><%= link_to "Repost", repost_post_path(post), method: :post, data: { confirm: "Are you sure?"} if user_signed_in? %></div>
<% end %>
</div>
<div class="panel-footer">
<div class="comment-form">
<%= form_for([post, post.comments.build], remote: true) do |f| %>
<%= f.text_field :content, placeholder: 'Add a comment...', class: "form-control comment_content", id: "comment_content_#{post.id}" %>
<% end %>
</div>
<div class="comments" id= "comments_#{post.id}">
<% if post.comments.present? %>
<%= render post.comments, post: post %>
<% end %>
</div>
</div>
my _comment.html.erb in comments folder:
<% if comment.user_id.present? %>
<div id="comment">
<%= link_to image_tag(post.user.avatar.url, size: "30x30", class: "img-circle img-comments"), profile_path(comment.user.user_name) %>
<div class="user-name">
<%= link_to comment.user.user_name, profile_path(comment.user.user_name), class: "username-size" %>
</div>
<div class="comment-content">
<%= comment.content %>
</div>
</div>
<% end %>
and here is the create.js.erb under comments folder :
$('#comments_<%= #post.id %>').append("<%=j render 'comments/comment', post: #post, comment: #comment %>");
$('#comment_content_<%= #post.id %>').val('')
and my comments controller:
class CommentsController < ApplicationController
before_action :set_post
def index
#comments = #post.comment.all
end
def new
#comment = #post.comments.build(comments_params)
end
def create
#comment = #post.comments.build(comments_params)
#comment.user_id = current_user.id
if #comment.save
respond_to do |format|
format.html { redirect_to root_path }
format.js
end
else
flash[:alert] = "Check the comment form, something went horribly wrong."
render root_path
end
end
def destroy
#comment = #post.comments.find(params[:id])
#comment.destroy
flash[:success] = "Comment deleted :("
redirect_to root_path
end
private
def comments_params
params.require(:comment).permit(:content)
end
def set_post
#post = Post.find(params[:post_id])
end
end
I don't think this line is right -
<div class="comments" id= "comments_#{post.id}">
I think you need this
<div class="comments" id= "comments_<%= post.id %>">
I want to get ".comment_container" for the post just made and place it after the last comment.
Each comment and it's related content is stored in a ".comment_container" class.
The code below does what I need but not 100%. Rather than append the word TEST I want to append the new comment_contaner holding the comment just posted.
I've been cracking at this all day and this is how far I've come. I would appreciate some solutions with examples if possible.
JQuery:
$('#new_comment').on('ajax:success', function(){
$(this).parent('.post_content').find('.comment_container:last').after("TEST");
});
<% sleep 1 %>
HTML:
<div class="postHolder">
<nav class="micropostOptions">
<ul class="postMenu">
<li class="deletePost"><%= link_to content_tag(:span, "Delete post"), m, :method => :delete, :confirm => "Are you sure?", :title => m.content, :class => "message_delete" %>
</li>
<li class="disableCommenting"><%= link_to content_tag(:span, "Pause commenting"), "2" %></li>
<li class="blockCommenter"><%= link_to content_tag(:span, "Block commenter"), "3" %></li>
<li class="openInNewWindow"><%= link_to content_tag(:span, "Open in new window"), "4" %></li>
<li class="reportAbuse"><%= link_to content_tag(:span, "Report abuse"), "5" %></li>
</ul>
</nav>
<%= link_to image_tag(default_photo_for_current_user, :class => "poster_photo"), current_users_username %>
<div class="post_content">
<div class="post_container">
<div class="userNameFontStyle"><%= link_to current_users_username.capitalize, current_users_username %> -
<div class="post_time"> <%= time_ago_in_words(m.created_at) %> ago.</div> </div>
<%= simple_format h(m.content) %> </div>
<% if m.comments.any? %>
<% comments(m.id).each do |comment| %>
<div class="comment_container">
<%= link_to image_tag(default_photo_for_commenter(comment), :class => "commenter_photo"), commenter(comment.user_id).username %>
<div class="commenter_content"> <div class="userNameFontStyle"><%= link_to commenter(comment.user_id).username.capitalize, commenter(comment.user_id).username %> - <%= simple_format h(comment.content) %> </div>
</div><div class="comment_post_time"> <%= time_ago_in_words(comment.created_at) %> ago. </div>
</div>
<% end %>
<% end %>
<% if logged_in? %>
<%= form_for #comment, :remote => true, :html => {:class => "new_comment} do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :micropost_id, :value => m.id %>
<%= f.text_area :content, :placeholder => 'Post a comment...', :class => "comment_box", :rows => 0, :columns => 0 %>
<div class="commentButtons">
<%= f.submit 'Post it', :class => "commentButton" %>
<div class="cancelButton"> Cancel </div>
</div>
<% end %>
<% end %>
</div>
</div>
Comments controller:
class CommentsController < ApplicationController
def create
#comment = Micropost.find(params[:comment][:micropost_id]).comments.build(params[:comment])
respond_to do |format|
if #comment.save
unless params[:comment][:recipient].blank? # this will be blank when current user is commenting/replying on their own wall
recipient = User.find(params[:comment][:recipient])
UserMailer.new_wall_post_comment_notification(recipient, current_user).deliver if recipient.email_notification == 1
end
format.js { render :post_comment }
else
format.js { render :form_errors }
end
end
end
end
Comment partial:
<div class="comment_container">
<%= link_to image_tag(default_photo_for_commenter(#comment), :class => "commenter_photo"), commenter(#comment.user_id).username %>
<div class="commenter_content">
<div class="userNameFontStyle"><%= link_to commenter(#comment.user_id).username.capitalize, commenter(#comment.user_id).username %> - <%= simple_format h(#comment.content) %>
</div>
</div>
<div class="comment_post_time">
<%= time_ago_in_words(#comment.created_at) %> ago.
</div>
</div>
Seems to be working apart from 1 minor issue. Let's say I post 4 comment... 1 after each other. First comment 1, second 2, third 3 and fourth 4.. e.g. 1, 2, 3 and 4 the result I get is this:
I have a feeling it's something to do with some kind of reset needing to be done after each comment is left. After refreshing the comments display as expected. 1, 2, 3 and 4. Any thoughts?
Kind regards.
You should make the partial for rendering your Comments (I guess it should be the /views/comments/_comment.html.erb).
Then just replace:
.after("TEST");
with:
.after("<%= j render #comment %>");
This along with the advice from jdoe fixed my issue
$('.new_comment').off().on('ajax:success', function(e){
e.preventDefault();
$(this).parent('.post_content').find('.comment_container:last').after("<%= j render 'comments/partials/comment' %>");
$('#comment_content').removeClass("comment_box_focused").addClass("comment_box");
$(".commentButtons").removeClass("displayButtons");
$('#comment_content').val("");
<% sleep 1 %>
});