I want to show user activity history which could be huge in AJAX way.
Basically I follow this guide, with improvement from this guide
<div class="container">
<%= render partial: "home/activity", collection: @activities %>
</div>
<div class="load-more-container">
<%= image_tag "ajax-loader.gif", style: "display:none;", class: "loading-gif" %>
<%= link_to "Load More", "#", class: "load-more"%>
</div>
Please note
1. the partial is under views/home/
instead of views/activities
by default. So we need to specify the path, instead of using <%= render @activities%>
directly.
2. don't add remote: true
in the link_to
tag, otherwise, it will fetch twice, one with id, the other one without, leading to duplicate result.
3. download the ajax-loader.gif to assets/images
default_scope { order('id DESC') }
I use ID instead of created_at because we do not have index for created_id. Usually, the ID order should be same with created_at, with some corner case exceptions.
<div class="record" data-id="<%= activity.id %>">
<%= activity.id %> | <%= activity.operation %> | <%= activity.table.name %> | <%= activity.record_id %> | <%= activity.updated_at %>
</div>
Please not that you must specify the class
and data-id
attribute, which are use by the Javascript below.
$(document).on("turbolinks:load", function() {
// when the load more link is clicked
$('a.load-more').click(function (e) {
console.log("Load-more clicked")
// prevent the default click action
e.preventDefault();
// hide load more link
$('.load-more').hide();
// show loading gif
$('.loading-gif').show();
// get the last id and save it in a variable 'last-id'
var last_id = $('.record').last().attr('data-id');
console.log(`Last ID: ${last_id}`)
// make an ajax call passing along our last user id
$.ajax({
// make a get request to the server
type: "GET",
// get the url from the href attribute of our link
url: $(this).attr('href'),
// send the last id to our rails app
data: {
id: last_id
},
// the response will be a script
dataType: "script",
// upon success
success: function () {
// hide the loading gif
$('.loading-gif').hide();
// show our load more link
$('.load-more').show();
}
});
});
});
def activities
if params[:id]
@activities = Activity.where(user: current_user, id: (0..params[:id].to_i-1)).limit(5)
else
@activities = Activity.where(user: current_user).limit(5)
end
respond_to do |format|
format.html
format.js
end
end
Please note that the class variable solution here does not work, reloading the page will not reset the class variable, leading to empty page.
<% if @activities.empty? %>
$('.load-more-container').hide()
<% else %>
$('.container').append('<%= escape_javascript(render(partial: "home/activity",collection: @activities)) %>')
<% end %>
Please note that we use the solution here to disable the link once all loaded. It depends on the class container
and load-more-container
set in views/home/activities.html.erb