AJAX micropost's comments on the user page - javascript

On the user's page there are microposts and each of them have it's own comment form and comments. Using "Endless Page" railscast i'm trying to create "show more comments" button, which will load comments by AJAX. But it's not working.
The problem is in show.js.erb file because:
1) common pagination of comments (without AJAX) is working well
2) "show more button" is working well too. I tested it on the users list page
I think "show more comments" not working because it don'understand <%= j render(comments) %> , <%= j will_paginate(comments) %> and i should have here variables like <%= j render(#comments) %> , <%= j will_paginate(#comments) %>.
But when i try to write in my users_controller.rb
def show
#micropost = Micropost.find(params[:micropost_id])
#comments = #micropost.comments
end
it's not working because on my user's page there are many microposts and i have an error "Couldn't find micropost without an id". So in my microposts/_micropost.html.erb i had to use this
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<%= render comments %>
Can anyone please help? How should i change my show.js.erb?
users/show.html.erb
<%= render #microposts %>
microposts/_micropost.html.erb
...
micropost's content
...
<%= render 'comments/form', micropost: micropost %>
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<div class="commentaries">
<%= render comments %>
</div>
<div id="append_and_paginate">
<%= will_paginate comments, :class =>"pagination", :page_links => false %>
</div>
javascripts/users.js.coffee
jQuery ->
if $('.pagination').length
$('#append_and_paginate').prepend('<a id="append_more_results" href="javascript:void(0);">Show more</a>');
$('#append_more_results').click ->
url = $('.pagination .next_page').attr('href')
if url
$('.pagination').text('Fetching more...')
$.getScript(url)
users/show.js.erb
$('.commentaries').append('<%= j render(comments) %>');
<% if comments.next_page %>
$('.pagination').replaceWith('<%= j will_paginate(comments) %>');
<% else %>
$('.pagination').remove();
<% end %>
<% sleep 0.3 %>

Bennington, in users/show.html.erb you have
But #microposts is not defined in your controller. What I think you want is to define #microposts as all the microposts associated with what, a User?
If so, you'd want something like `#microposts = Micropost.where(:user_id => current_user.id) or something.

Related

Rails 5, simple javascript with form submit

I am hoping someone can help me here. Been at this for a few hours, but can't seem to figure out why my Javascript is not working on my simple form. I'm simply trying to display comments using the ajax call. I have gem 'jquery-rails', and required jquery, and jquery_ujs in my application.js file. Here's the code I have so far:
I have a Joy model that has_many comments.
<% #joys.each do |joy| %>
<ul id="comments-<%= joy.id %>">
<% joy.comments.where(void:'f').each do |comment| %>
<li><%= comment.body %></li>
<% end %>
</ul>
<%= form_with(model: [ joy.user, joy, joy.comments.build ], data:{ "js-comments-#{joy.id}" => true}) do |f| %>
<%= f.text_area :body, :class=>'form-control', :required=>'true' %>
<%= f.submit "Post Comment" %>
<% end %>
<script>
$(document).ready(function() {
$('[data-js-comments-<%= joy.id %>]').on("ajax:success", function(event, data, status, xhr){
$('#comments-<%=joy.id%>').append(xhr.responseText);
});
});
</script>
<% end %>
In my Comment controller, in my 'create' action, I have:
if #comment.save
render partial: "comment", locals: {comment: #comment}
end
In my Comment views, I created a partial, called _comment.html.erb:
<li>
<%= comment.body %>
</li>
So, now when I enter a comment, and click 'Post Comment', it correctly saves my Comment, but it does not ajax load the comment into list. Furthermore, the form does not refresh either. The text remains in the text box. It is not only until after I refresh the page when my comment shows up in the list. Anyone with any thoughts on what I'm missing or doing wrong???
Your help is greatly appreciated in advance.
form_with it's a remote form, you dont need that block <script>..</script>.
Just use create.js.erb then use jquery to append new comment.
And if you want to check if your message was created successfully, you can add a #status value in your controller.
//comments_controller.rb
def create
...
if #comment.save
#status = "success"
else
#status = "failed"
end
...
end
//create.js.erb - for example
$("#yourCommentList").append('<%= j( render partial: 'comments/comment', locals: #comment ) %>');
<% if #status == "success" %>
$("body").append(...your notification...)
...
<% else %>
...
<% end %>

Rails 5 using will_paginate to create a load more button

So I'm trying to create a load more button (not infinite scroll although some simple js tweaks could make it so). I'm using the will_paginate gem in Rails 5.
Its currently all working as expected except when I click load more it loads the next page posts twice e.g:
Load more >
Post 4,
Post 5,
Post 6,
Post 4,
Post 5,
Post 6
FYI my 'posts' are #links:
links_controller.erb
def index
#links = Link.order('created_at DESC').paginate(:page => params[:page], :per_page => 3)
respond_to do |format|
format.html
format.js
end
end
views/links/index.html.erb
<div class="link-wrap">
<%= render #links %>
</div>
<% if #links.next_page %>
<div class="link more">
<%= link_to 'Load More', links_path(:page => #links.next_page), :class => 'next_page', :remote => true if #links.next_page %>
</div>
<% end %>
pagination.js.coffee
$ ->
$('.next_page').on 'click', (e) ->
e.preventDefault()
url = $(this).attr('href')
$.getScript(url)
index.js.erb
$('.link-wrap').append('<%= j render(#links) %>');
<% if #links.next_page %>
$('.next_page').attr('href','<%= links_path(:page => #links.next_page) %>');
<% else %>
$('.more').remove();
<% end %>
For the life of me I can't figure out why it would be rendering the links twice when 'load more' is clicked. This seems like a really simple thing but I'm struggling.
So it was a stupid error of course.
Remove the line on index.html.erb:
:remote => true if #links.next_page
So now it looks like this:
<div class="link-wrap">
<%= render #links %>
</div>
<% if #links.next_page %>
<div class="link more">
<%= link_to 'Load More', links_path(:page => #links.next_page), :class => 'next_page' %>
</div>
<% end %>
All works fine now!
If you check the server console, you can actually see two requests coming in, one triggered by your :remote => true enabled link and other from your custom ajax. Actually you don't need any js to make this work. Just remove that click function from your pagination.js.coffee or remove :remote => true from the link. After all both are doing the same thing. Hope this will help.

Rails will_paginate two objects on the same page, passing one param from search field

I am using will_paginate on the results from two instance variables, each using the same param[:query] on two different PgSearch.multisearch methods. In the views, when clicking on one of the pagination links, both the tables were being updated. Is there any way to get around this problem? By passing only one param from the form? (As my search form has only one text field). I have searched and gone through the similar questions, most of them suggesting to use two params., but none of them gave me any thoughts to solve this prob using one param. :/
Code in the form:
<%= form_tag("/search", :method => "get", :remote => true) do %>
<%= label_tag(:query, "Search for: ") %>
<%= text_field_tag(:query, params[:query]) %>
<%= submit_tag("Search", class: "btn btn-primary") %>
<% end %>
Controller code:
def index
#employee = Employee.find(session[:user_id])
#search_employees = PgSearch.multisearch(params[:query]).where(:searchable_type => "Employee").paginate(page: params[:page], :per_page => 5)
#search_customers = PgSearch.multisearch(params[:query]).where(:searchable_type => "Customer").paginate(page: params[:page], :per_page => 5)
respond_to do |f|
f.html
f.js
end
end
Code in the View:
<% if !#search_employees.empty? %>
<h2>Employees</h2>
<table class="table table-hover">
.
.
<% #search_employees.each_with_index do |doc, index| %>
<% user = doc.searchable %>
<tr id="employee-<%= user.id %>">
.
.
<% end %>
</tbody>
</table>
<% end %>
<%= will_paginate #search_employees %>
<% if !#search_customers.empty? %>
<h2>Customers</h2>
<table>
.
.
</table>
<% end %>
<%= will_paginate #search_customers %>
Can I send two different params with the same text field value from the form? if so., please let me know how. Any ideas or suggestions would be much appreciated. :)
Thanks in Advance. :)
Pagination depends on the page parameter, but not on the query parameter from the search form, therefore you don't need to change anything in your form.
To update only corresponding table you need to customize page parameter in at least one of the tables. For example change page parameter for customers:
<%= will_paginate #search_customers, :param_name => 'customers_page' %>
and in controller:
#search_customers = PgSearch.multisearch(params[:query])
.where(:searchable_type => "Customer")
.paginate(:page => params[:customers_page], :per_page => 5)
This should resolve the issue

Part of form not showing issue

I have a rails 4 app where I'm following basically this railscast:
_form.html.erb:
<%= form_for #store, do |f| %>
<%= f.fields_for :products do |builder| %>
<%= render "product_fields", f: builder %>
<% end %>
<%= link_to_add_fields "Add Product", f, :products %>
<% end %>
_product_fields.html.erb
<%= f.select :the_product_type, %w[Shelves, Tools, Wires]%>
<div>
<%= f.fields_for :product_fields do |builder| %>
<%= builder.text_area :name_of_product_field %>
<% end %>
</div>
My JS looks like:
$('form').on('click', '.add_fields', function(e) {
var regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$(this).before($(this).data('fields').replace(regexp, time));
return e.preventDefault();
});
My issue is that when I click the Add Product button, I can only see a select. I can't see the name_of_product_field textarea. But I can't figure out why I can see the select if I can't see the textarea?
product_fields is a nested attribute which you have not build anywhere in your code which is why you are not seeing it.
Assuming that a product has_many product_fields, you can resolve this issue in two ways, choose one that suits you:
1. Build it at Controller level
Build the product_fields in the Controller#action which is rendering the problematic view:
def action_name
#store = Store.new
product = #store.products.build
product.product_fields.build
end
2.Build it at View level
Update the fields_for in _product_fields.html.erb as below:
<%= f.fields_for :product_fields, f.object.product_fields.build do |builder| %>

Why does my js.erb file only run in one of these situations?

I have the following action on my controller for a Comment:
def create
#comment = comment.new(params[:comment])
#comment.replyable_type = params[:replyable_type]
#comment.replyable_id = params[:replyable_id]
#comment.user = current_user
respond_to do |format|
format.html do
# Removed
end
format.js do
#comment.save
end
end
end
and the following create.js.erb file for when it gets called by a remote form:
console.log('It did run');
<% if #comment.errors.any? %>
<% #comment.errors.full_messages.each do |msg| %>
console.log('<%= javascript_escape(msg) %>');
<% end %>
<% else %>
comment = "<%= escape_javascript render #comment %>";
<% if #comment.replyable_type == 'Comment' %>
$('#comment-<%= #comment.id %> > .replies').prepend(comment));
<% else %>
$('.comments').prepend(comment);
<% end %>
// removed
<% end %>
Along with the following form partial:
<%= form_for(Comment.new, url: comments_path, remote: true) do |f| %>
<div class="comment-form" id="comment-<%= replyable_type %>-<%= replyable_id %>">
<%= f.text_area :content, cols: 60, rows: 5 %>
<%= hidden_field_tag :replyable_id, replyable_id %>
<%= hidden_field_tag :replyable_type, replyable_type %>
<%= f.submit 'Send Comment', class: 'btn btn-primary' %>
</div>
<% end %>
replyable is a polymorphic association, which can be either a Post or a Comment object. When I submit a copy of the form on a page for a post, where replyable_type is Post and replyable_id is a post's ID, it works fine. When I submit a copy of the form on the same page, with the replyable_type set to Comment, and the replyable_id set to a comment's ID, the view the javascript does not run, at all. The action on the controller runs, using Firebug I can see the rendered javascript being sent back in response to the post request, and the comment is added to the database.
There are no errors in either the Rails console for generating the javascript or in the Firebug console to do with running the generated javascript. There are also no errors in the #comment.errors array. Even the first console.log in the Javascript is not run when the replyable object is a comment, despite being present in the rendered javascript.
What could cause this? I am using Rails 3.2.13 on Ruby 1.9.3

Categories

Resources