Todo List - Building a React App with Rails API

Payam Mousavi
7 min readOct 12, 2018



Ruby On Rails is one of the popular web frameworks which enables developers to build amazing web applications. Rails 5 introduced API-only mode to create RESTful backends easily. On the client side, React has become a famous client-side framework among frontend developers, providing them with its great lifecycle methods and async functions. In this tutorial, we aim to build a Todo List app with the help of React and Rails.


We will first build the Rails backend which talks in JSON! Then we’ll set up the React project to fetch/store data using the backend. This is an overview of what we are going to create:

Backend: Rails 5 API

I want to skip the part about installing Ruby and Rails and assume you already have the latest versions. I’m using Ruby 2.5.0 and Rails 5.2.1. First, we generate the backend code using rails new command:

rails new todo-api --apicd todo-api

Open the project using your favorite editor. Then open Gemfile and add rack-cors:

gem 'rack-cors', :require => 'rack/cors'

You can read more about CORS.

NOTE: If you want to deploy the app later (for example, on Heroku), move sqlite3 to the development group and add pg gem to a production group to use Postgresql:

group :development, :test do
gem 'sqlite3'
group :production do
gem 'pg'

Then in your Terminal/Console:

rails generate model Todo title:string done:booleanrails generate controller Todos index create update destroyrails db:migrate

These commands generate a Todo model and a Todos controller, and the last command generates the data table (todos) in the sqlite local instance.

Now we are ready to do some coding! Let’s start with route.rb. If you open the file, you’ll see that there are 4 routes. As we are going to define our own routes for the APIs, remove them and use scope to define the new routes/APIs:

Rails.application.routes.draw do
scope '/api/v1' do
resources :todos

Using resources means we want all the actions (POST, PUT, GET, DELETE).

Let’s continue with the controller. We should implement the logic for those actions we just defined.

We are done! You just need to start the server:

rails server

And if you visit http://localhost:3000/api/v1/todos you’ll see a blank screen! There’s no data so we can add some todo items to check the API. We do that by changing db/seeds.rb file:

Todo.create(title: "Buy food: milk, bread, fruits", done: false)Todo.create(title: "Imagine Dragons tickets", done: false)

And then run:

rails db:seed

Now refresh your page and you should see the data in JSON format:

You can install any JSON viewer extension on your browser to see formatted data.

Congratulations! The backend is done. Now, we should start working on the frontend with React. Stop the rails server for now. We will run the server on port 3000 and the React app on port 4000.

We will use Heroku CLI to run our app locally. It can also be used to deploy the app to production environment. You can read more about Heroku local. Let’s create a file called with the following content:

web: PORT=4000 yarn --cwd todo-app start
api: PORT=3000 bundle exec rails server

Don’t worry about the commands for now. Just know that the first command tells Heroku to run the React app and the second command runs the Rails server. You can read more about Procfile.

Frontend: Reactjs

We are going to use Create React App to create our React frontend. You need Node.js to install that package. I’m using Node v10.11.0. Install create-react-app globally and then create the React project:

npm install -g create-react-appcreate-react-app todo-app

NOTE: If you haven’t installed yarn yet, now it’s a good time! It’s a fast package manager.

Now you see a new directory in your Rails project — todo-app. It’s time to run the React app:

yarn --cwd todo-app start

The above command runs the React app which is in the todo-app directory. You should see the default React page:

Now we need to tell our React app to use the backend service on a specific port in development mode. Open todo-app/package.json and add this line:

"proxy": "http://localhost:3000"

This tells React to talk to the backend via a proxy on port 3000 in development mode. When we want to call our todos APIs — "http://localhost:3000/api/v1/todos" — from the app, we just need to specify "/api/v1/todos".

This is my package.json file:

You remember we created a file? It’s time to use it by calling:

heroku local -f

This runs the Rails API and the React app. This will also open http://localhost:4000.

React Components

One of the main advantages of React is the concept of Components. According to React website:

Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.

We are going to create our first component. Let’s create a new file in todo-app/src/components/TodosContainer.js:

Let’s update App.js to import this newly created TodosContainer:

Now update App.css:

Open http://localhost:4000 and check the result

Calling APIs

It’s time to load the data from the backend. You can use any package to fetch/store data. I use axios. Install axios and import it in TodosContainer:

cd todo-appnpm install axios --save

Get Todos

We need to update TodosContainer to initialise the state which specifies the behaviour of a component. Also, we add componentDidMount function to load the list of todos:

Now restart heroku local. Congratulations! We managed to load our todo list.

Create Todo

Next, we’ll call POST /api/v1/todos to create a new todo item. We need to create a new function to do that and also to update the state. To update the state, we use immutability-helper. Let’s install the package and import it in TodosContainer:

npm install immutability-helper --save

Now update the textbox to have an onKeyPress event:

Then the function:

We used $splice function to add the new item at the first index of the todos array. Now add a new item yourself to see the magic!

After you add an item, you see that the value of the textbox is still there. To update it, we should define another parameter in the app state:

Then update the createTodo function to update the state with this new parameter:

Add a new handleChange function which will be called when the textbox value changes:

And finally update the textbox to have new attributes:

Update Todo

How about marking an item as DONE? Let’s do it. We should update the checkbox element and create an update function:

You noticed that the way we call updateTodo is different. That’s because we want to pass id of the item. To update the state, we used $set function to update the item after finding its index. Go ahead and test it.

Remove Todo

The last piece of the puzzle is deleting an item. First let’s update the span element:

Then create a deleteTodo function:

We used $splice again but this time to remove the item with todoIndex.

Congrats! The app is ready.


We created a Todo app using React as the frontend and Rails as the backend. Setting up the React project with Create-React-App was super easy. We created our first React component — TodosContainer. We also used the React state to manage the behaviour of the app. Rails has made it really easy and clean to create a backend project which only speaks JSON so we can spend more time on tuning the frontend app. Next, we can work on deploying the app on Heroku or other production hosts. We can also create other components (e.g. Todo) and use them in the containers.

For the sake of simplicity, the main container of this app was also responsible to render the UI elements (usually the job of a component), so that we could focus on main concepts and data flow. You can read Dan Abramov article for more information.

I hope you enjoyed this article. You can download the source code from my Github: pamit/react-rails-todo-app.

Happy coding!