Blog

Smart table with searching, sorting, pagination using ReactJS in…

Ruby on Rails powers a lot of products at Geogo. We’ve started from Rails v4 and over the time developed many applications using this powerful web framework. Usually when we work on a complex application, a common UI component that comes again and again in every second page is, a Smart Table. A data table with features like searching, sorting, filtering and pagination in AJAX. And till Rails 5 our hot pick for this component was smart_listing gem, which provided those features out-of-the-box.

What’s the problem then? — let me explain

On August 2019 Rails 6 got released, which came with a lot of exciting features like Action Mailbox, Action Text, Multiple database support, Parallel testing and most importantly Webpack as a default bundler through the webpacker gem. Webpacker replaced the previously-default Rails Asset Pipeline and it’s now providing better interoperability with modern JavaScript libraries (like React, Vue, Angular) and coding standards. 

And the bad news is, with this major release smart_listing got deprecated and till the day i’m writing this article they haven’t published any update yet. I’ve tried many hack to include smart_listing in a Rails 6 app, but none of them were working as expected.

Getting started —with the plan

We will create a simple product listing application which would feature Smart Data Tables with all above mentoined features, using ReactandRedux. We would separate API endpoints to power those tables.

You can also consider this implementation as an example of How to use ReactJS in Ruby on Rails?.

Let’s dive — into the implementation

Installation 

  1. Generate a new Rails 6 application
rails new smart-table-in-rails-with-react -d postgresql
  •  The -d flag specifies the preferred database, which in this case is PostgreSQL, you can also opt for MySQL or SQLite.

After generating a new application, few basic configurations need to be accomploshed, like: database, secrets, storage etc. I’m not getting into those details.

2. Initiate ReactJS using webpacker

bundle exec rails webpacker:install:react

This command instruct Rails to configure a React application inside. Once it’s done running, it would generate a new file app/javascript/packs/hello_react.jsx. This file holds sample code of a basic React app which you can run byadding <%= javascript_pack_tag ‘hello_react’ %> to the head of your layout file.

3. Install Frontend dependencies

In this step, we would install the JavaScript dependencies needed on the frontend of our application. They include:

Run the following command to install these packages with Yarn:

yarn add react-router-dom redux react-redux redux-thunk redux-form @material-ui/core

Setting up Rails to load the React app

  1. First we have to create a new layout file, app/views/react.html.erb with the following content.
<!DOCTYPE html>
<html>
<head>
<title>Products - Powered by React</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_pack_tag 'application' %>
<%= javascript_pack_tag 'hello_react' %>
</head>
<body>
<main id="reactAppContainer">
<%= yield %>
</main>
</body>
</html>

2. Now let’s generate a new Product model with the following command:

rails g scaffold Product name price:float is_active:boolean

Once you run the migration using rails db:migrate, you’ll be able to perform CRUD operations on Product.

3. Set the homepage to products#index page in routes file

root ‘products#index’

Then start rails server with rails s and add few products to database.

Note: Open another tab in terminal and run ./bin/webpack-dev-server. Here you will be able to check if the Javascript bundle is compiling properly or not.

4. Resolve react layout for index action in products_controller.

class ProductsController < ApplicationController
layout :resolve_layout
...
...

private
def resolve_layout
case action_name
when "index"
"react" # Load react layout for index action
else
"application" # Load application layout for other actions
end
end # End of resolve_layout
end