In this tutorial, we’re going to look at integrating React into an existing Rails 5.2 app with the react on rails gem, in order to provide an optimal user experience and keep our codebase clean at the same time.
Suppose you are running your own app store called AppGarage. Users are able to see popular apps, download them, and search for new apps.
Currently, the website is built only with Ruby on Rails so users have to type the whole search term, submit, and wait for a page refresh before seeing the search results.
Users expect content to be loaded as they type so that they can find apps faster. Wouldn’t it be nice to upgrade our search functionality to dynamically fetch and render search results as the user types their query? Let’s do that with React!
Table of Contents
Ensure the followings are installed on your device:
- Ruby on Rails v5.2 or greater
We begin by cloning the repository for our project from GitHub which includes the entire static website built with Ruby on Rails and no react integration.
Use the following command to clone the repository:
$ git clone https://github.com/danielrudn/app-garage
After cloning, enter the
$ cd app-garage
Migrate and Seed the Database
Now that we pulled down the code for our project, we must prepare rails by migrating and seeding our database:
$ rails db:migrate && rails db:seed
Our database now has the correct schema and is seeded with initial sample data in order to easily visualize our code changes. We can now start the rails server (Note: it may take rails a while to start the server on its first run):
$ rails server
You can now head over to
http://localhost:3000 and you’ll see that our base application is working. We can view the homepage, search for apps, and view specific apps.
Now that we have a working web app, we’re ready to improve it by integrating React on Rails and modifying the search functionality.
Installing React on Rails
Note: If you’re following this tutorial using a different existing Rails app or if you’re using a Rails version older than 5.1 you should take a look at the official react-on-rails documentation for integrating with existing rails projects.
Adding and Installing Gems
First, we must add the
mini_racer gems. Edit the
Gemfile and add the following to the bottom of the file:
After adding the gems to the
Gemfile, install them with the following command:
$ bundle install
Setting up Webpacker and React
Now that the required gems are installed, we can begin configuration. First, we configure Webpacker by running:
$ bundle exec rails webpacker:install
Now that webpacker is configured, we install and configure React:
$ bundle exec rails webpacker:install:react
We should now see the following in our terminal:
Webpacker now supports react.js 🎉
Note: We can delete the autogenerated sample file:
Setting up React on Rails
Currently, our project has Webpacker and supports React but we do not have an integration between React and Ruby on Rails. We need to add our changes to version control, so we add all of our changes and commit with the following command (Note: it’s important to commit our changes otherwise we will get warnings when continuing the tutorial):
$ git add . && git commit -m "Add webpacker & react"
react_on_rails packages to our
package.json by running:
$ yarn add react-dom react-on-rails
config/initializers/react_on_rails.rb with the following content:
Implementing the Search Component
Starting simple, we’re going to take our current search view and have it render as a React component without changing any functionality.
Create the following structure in your application folder:
We can now create our search component called
Search.jsx inside the folder we just created with the following content:
The above is our markup for searching converted to JSX in order for React to render it as a component. Note that we changed the HTML
autocomplete attributes to
We now have a search component but React on Rails knows nothing about it. Whenever we create a new component that we want to use in our Rails app, we must register it with react-on-rails in order to be able to use it with the
react_component rails helper. To do so, we edit the
application.js file now serves as a way for us to register our components with react-on-rails. In our case, it’s acceptable to include our search component on every page load, but for real-life production applications, it’s not very performant to include every component on every page. In real-life applications, components would be split into webpack bundles which are loaded on pages where they are needed.
Now we include our application bundle in our layout on every page by editing
app/views/layouts/application.html.erbto have the following content:
Now, we’ll replace our homepage markup with the react-on-rails
react_component helper to render our Search component by editing
app/views/home/index.html.erb to have the following content:
Adding React Functionality to our Replacement
Our search is now rendered as a react component but all of our functionality has remained the same, the only difference is not noticeable to users yet. We’re now able to start making our search dynamic.
We need to be able to fetch our search data as JSON but we currently don’t have a JSON endpoint for our search controller. To do this, we add the file
app/views/search/index.json.jbuilder with the following content:
Now our search data is accessible as JSON via
axios library since it also supports older browsers. To install the library, simply run the following command in your terminal:
$ yarn add axios
Now that we have our dependencies installed, we can begin improving our search component. We must start tracking the text written into the search field, fetching the search results for the current text, and updating the state. Here is the new content for
- To start, we defined our components state (and initial state) to include our search results and whether or not we’re currently loading/fetching new results.
- Next, we wrote our
onChange function which gets called each time the value in the search field changes. We use axios to send an http request to our new
/search.json endpoint with the current search field text. Axios will either successfully fetch results in which case we update our state to include the results, or it will fail and we update our state to have no results.
- Our render function stays almost the same. We alter the input field by adding an
onChange handler and pointing to the
onChange function we just wrote.
The updated search component now dynamically stores and fetches the users search results based on the current text but doesn’t render anything related to the results yet.
Rendering the Dynamic Search Results
In order to render the search components state, we will create two new components that will make our code easier to manage.
First, we create the
SearchResult component which is a purely functional component with no state and it renders declaratively based on props. The prop we expect is a
result which is a regular
app object from our rails application. Create
Now, we create a
SearchResultList which is also a purely functional component in order to render our result array as
SearchResult components. The
SearchResultList will expect two props, the first is
results, an array of our search results and the second is whether or not we’re currently
loading new results. Create
SearchResultList will iterate through our search results and map them to render as a
SearchResult component. We added a style attribute to the container in order to properly display the results under our search field.
Now that we have our two helper components we can modify
Search.jsx to render its state when the result array is not empty. Update
The changes we made to the
Search component were:
- Imported our
- Updated the
render function to render the
SearchResultList component when we have results or when we are loading.
We’ve now integrated React on Rails into our Rails 5.2 app in order to have a dynamic search component for our users.
We started with a regular rails application and went through the process of installing and configuring Webpacker, React, and React on Rails. After configuring, we replaced our search to be a react component which dynamically fetches and renders search results from a new JSON endpoint on our Rails app.
The original implementation above wasn’t a good user experience since it involved typing the full query, waiting for the page to load before seeing any results.
The new implementation above shows search results as the user types which saves time and provides a much better user experience.
We can now begin adding even more interactivity to our website by implementing additional react components and reusing existing components on other pages.
Preview Final Version
You can preview the final version by following these steps:
- Clone the
final-version branch of the GitHub Repository
$ git clone -b final-version https://github.com/danielrudn/app-garage
- Enter the newly cloned
$ cd app-garage
- Run the necessary setup commands:
$ yarn && rails db:migrate && rails db:seed
- Start the rails server and navigate to
http://localhost:3000 Note: Initial load may time a while.
$ rails server
If you want to learn more about integrating react with Ruby on Rails (such as proper state management with Redux or handling bundles for specific pages), the repository and documentation for react on rails is a great place to look.
Let’s block ads! (Why?)