Easy Ajax Infinite Scroll with Ruby On Rails and MooTools
Modern web design trends are going far from classic numbering pagination. Facebook, Twitter, Tumblr: all of them chose the infinite scroll paradigm to show more contents.
There are mainly to different cases in that technique: update content on user explicit action (like click on a button) or when user’s reach the end of page.
For a matter of User Experience and Usability, I generally prefer the first one, specially if you got a footer.
Anyway, this effect is easily obtained with a bit of Rails3 code and MooTools magic, so let’s make some assumptions:
- You have a Post model with relative controller and view
- You have a index method in your controller
- You’re using Rails3 plugin for MooTools
Infinite loop will show posts from last one to older, so let’s define the default scope in Post model:
models/post.rb
default_scope order('posts.created_at desc')
Let’s begin with the index method:
controllers/posts_controller.rb
def index
@posts = Post.limit(10)
@posts.length
respond_to do |format|
format.html
end
end
So we’re limiting the number of posts loaded. At this point let’s take a look at the view
views/posts/index.html.erb
<%= link_to "Load more..", {:action => :load_from, :start => @posts.last.id},{ :remote => true, :id => "pageLoader" } %>
We’re basically creating a link (remote, so using Ajax) to perform an HTTP GET request passing a certain id as parameter, handled by a custom action that we’re going to define in posts controller:
controllers/posts_controller.rb
def load_from
@start_point = params[:start]
@start_point = @start_point.to_i -1
@new_posts = Post.where('id < ?', @start_point).limit(10)
respond_to do |format|
format.js
end
end
So we're selecting the rest piece of data and manage a response for a js request. The javascript file, by convention over configuration, is located in the related view with the same name of the method's called:
views/posts/load_from.js.erb
var postsHtml = '<%= escape_javascript(render(@new_posts)) %>';
var el = new Element('div', {'html': postsHtml}).inject(document.id('posts'));
document.id('pageLoader').set('href', '/ajax/more?start=<%= @new_posts.last.id %>');
rails.applyEvents(el);
So we're creating the new element and injecting into posts container.
Then with the set('href') function we update the last post index on the 'load more' link in the view.
Finally, we attach rails3 events to our new created elements by calling function rails.applyEvents(el).
