DEV Community

Cover image for Create Seamless Loading in Ruby on Rails
John Kevin Baluyot
John Kevin Baluyot

Posted on

Create Seamless Loading in Ruby on Rails

Do you want your rails app to automatically load the next page when scrolled to the bottom? That's what we're covering in this post. We will create a rails app like Pinterest in Rails 6.

  1. Create the Image scaffold.

    $ rails g scaffold Image url:string author:string
    

    This will generate the necessary files for the rails app. You
    don't need to know most of them. We will be editing only some
    of the files.

    To create the image table, run this on your terminal:

    $ rails db:migrate
    
  2. Edit config/routes.rb.

    Rails.application.routes.draw do
     root to: "images#index"
    end
    

    This way the root page would use image#index by
    default (localhost:3000).

  3. Edit db/seeds.rb

    require "net/http"
    
    url = "https://picsum.photos/v2/list?page=2&limit=100"
    resp = Net::HTTP.get_response(URI.parse(url))
    data = JSON.parse(resp.body)
    
    data.each do |d|
     url = "https://picsum.photos/200/#{300+(rand(1..5)*20)}" #This will use random heights for the image
     p Image.where(author: d['author'], url: url).first_or_create
    end
    

    The URL, "https://picsum.photos/v2/list?page=2&limit=100" will return 100 random images that we will be using as seed for our rails app. For more information about this you could check it here.

    Then run in your terminal:

     $ rails db:seed
    
  4. Update app/views/images/index.html.erb.

    <header class="container">
     <h1 class="element-stack">Pinterest Flow</h1>
     <p class="element-stack">Scroll down to load more data</p>
    </header>
    
    <div id="columns">
     <%- @images.each do |image| %>
      <figure>
        <img src=<%= image.url %>>
        <figcaption><%= image.author%></figcaption>
      </figure>
     <% end %>
    </div>
    
  5. Edit app/assets/stylesheets/images.scss or app/assets/stylesheets/images.css, depending on what's generated by the scaffold.

    @font-face{font-family:'Calluna';
    src:url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/callunasansregular-webfont.woff') format('woff');
    }
    body {
     background: url(//subtlepatterns.com/patterns/scribble_light.png);
     font-family: Calluna, Arial, sans-serif;
     min-height: 1000px;
    }
    #columns {
        column-width: 150px;
        column-gap: 15px;
        width: 90%;
        max-width: 1100px;
        margin: 50px auto;
    }
    
    div#columns figure {
        background: #fefefe;
        margin: 0 2px 15px;
        padding-bottom: 10px;
        transition: opacity .4s ease-in-out;
        display: inline-block;
        column-break-inside: avoid;
        min-height: 100px;
    }
    
    div#columns figure img {
        width: 100%; height: auto;
        border-bottom: 1px solid #ccc;
        margin-bottom: 5px;
        border-radius: 15px;
    }
    
    div#columns figure figcaption {
        font-size: .9rem;
        color: #444;
        line-height: 1.5;
    }
    
    div#columns small {
        font-size: 1rem;
        float: right;
        text-transform: uppercase;
        color: #aaa;
    }
    
    div#columns small a {
        color: #666;
        text-decoration: none;
        transition: .4s color;
    }
    
    @media screen and (max-width: 750px) {
        #columns { column-gap: 0px; }
        #columns figure { width: 100%; }
    }
    

    This CSS is from this.

    Also import it in application.css.

    /*
    * This is a manifest file that'll be compiled into application.css, which will include all the files
    * listed below.
    *
    * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
    * vendor/assets/stylesheets directory can be referenced here using a relative path.
    *
    * You're free to add application-wide styles to this file and they'll appear at the bottom of the
    * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
    * files in this directory. Styles in this file should be added after the last require_* statement.
    * It is generally better to create a new file per style scope.
    *
    *= require card
    *= require_tree .
    *= require_self
    */
    
    @import "images";
    
    

    This is the styling we would be using. You could check out your localhost to check if it is all okay.

  6. Add paginate for images using will_paginate gem. Add this to the Gemfile.

    gem 'will_paginate'
    

    Then run bundle install.

    $ bundle install
    
  7. Edit index action in app/controllers/images_controller.rb.

    # GET /images or /images.json
    def index
     @images = Image.all.paginate(page: params[:page], per_page: 15)
    end
    

    Create _images.html.erb in app/views/images with this code.

    <%- images.each do |image| %>
     <figure>
       <img src=<%= image.url %>>
       <figcaption><%= image.author%></figcaption>
     </figure>
    <% end %>
    

    Then edit app/views/images/index.html.erb.

    <div id="columns">
     <%=render partial: "images", locals:{images: @images} %>
    </div>
    
    <%= will_paginate @images %>
    

    This would make paginate working in our rails app.

  8. Add Jquery to Rails. Run this in your terminal.

    $ yarn add jquery
    

    Then add the code below in config/webpack/environment.js.

    const webpack = require('webpack')
    environment.plugins.prepend('Provide',
     new webpack.ProvidePlugin({
      $: 'jquery/src/jquery',
      jQuery: 'jquery/src/jquery'
    })
    )
    

    Require jquery in application.js file.

    require("jquery")
    
  9. Create jquery.pageless.js in app/javascript/packs with this code

    Then require it in the application.js file.

    require("jquery")
    require("packs/jquery.pageless")
    
  10. Add this code in app/views/images/index.html.erb.

    <script type="text/javascript" charset="utf-8">
     var totalPages = <%= @images.total_pages %>;
     var url = '<%= root_path%>';
     $('#columns').pageless({ totalPages: totalPages
                       , url: url
                       , loaderMsg: 'Loading more results'
                       });
    </script>
    
  11. Edit app/controllers/images_controller.rb.

    def index
     @images = Image.all.paginate(page: params[:page], per_page: 15)
    
     if request.xhr?
       render partial: 'images/images', locals:{images: @images}
     end
    end
    

Now check your localhost to see if it's running.

And that's it. We're done! 😃

If you want to check the code. You could do it here:
Github Repository

Oldest comments (0)