Make your Rails app real-time—in under ten minutes

Scott Domes
Code == Life
Published in
6 min readAug 1, 2017

It’s way easier than you think.

In my experience, you think you won’t need real-time functionality… until you do. Perhaps you want to add a chat feature, or simply sync data across users.

At MuseFind, we have several Rails APIs, but none of them worked real-time. This led us to a pattern where we would reload data after sending in a change, keeping our front-end in sync with the back-end an often tiresome task.

Looking for a better way, I decided to look into converting an existing Rails API into real-time. And found it was easy, efficient, and generally awesome.

Google Docs Lite… very Lite

In this tutorial, we’ll create a simple real-time Rails API, and hook it up to a JavaScript (React) front-end.

We’re going to be making a Google Docs clone. And by clone, I mean literally just a textarea that updates in real-time for all users.

Requirements

You should have some familiarity with Rails, but no need to be an expert. We’ll also be using React but no knowledge necessary there—full code samples will be provided.

We’re going to move fast here, so buckle up!

Setting Up Two Applications

For this section, you’ll need to have Node, Rails, yarn, and create-react-app installed on your machine.

From your terminal, cd into the directory where you want your apps to live.

Front End

Run the following commands:

create-react-app docs-frontend
cd docs-frontend
yarn add actioncable // Official Rails real-time support
yarn start

Done.

Back End

Run the following commands in a new terminal:

// Create Rails project in API mode (no folders for views and such)
rails new docs --api
cd docs
// Create model and controller
rails generate scaffold Note text:text
// Run database migrations
rake db:migrate

Done. Let’s create our first model, while we’re here.

rails c
// Inside of console, run the below:
Note.create!(text: 'Hello!')

Then, exit the console and start the app to test that everything is working:

rails server -p 3001

We now have our back-end and front-end running. Let’s make sure they can communicate.

Setting Up CORS

Inside our docs folder (the Rails app), go to our Gemfile and uncomment this line:

gem ‘rack-cors’

Stop your server, then run bundle install. One more thing: add the following code to config/application.rb, right below config.api_only = true:

   config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end

Now our Rails app can receive network requests. Start your server again, and let’s set up the front end!

Our App Component

Here’s what our simple app looks like:

Copy and paste the above into docs-frontend/src/App.js. Also add this to App.css for prettiness purposes:

textarea {
width: 500px;
height: 500px;
margin: 20px;
}

When you restart both your Rails server and your React app, you should see your first note loaded in:

Great, we’ve built a working React/Rails app. But it’s not real-time. Let’s get that done.

Making Rails Real-Time

This is what you came for, right?

Three things to be done:

  1. Add a real-time route
  2. Create a ‘channel’ (essentially, a real-time connection)
  3. Configure streaming and receiving data

Step 1 is super simple. Inside config/routes.rb, add the following before end:

mount ActionCable.server => '/cable'

Now if we try to connect via WebSockets to ‘/cable’, ActionCable will pick it up.

Step 2 is also super easy.

rails generate channel Notes

This will create a channels folder with notes_channel.rb inside. Open up that file, and we can take care of Step 3.

We’ve added stream_from to the #subscribed method, with the name of our channel (‘notes’).

Then, we’ve added a #receive method, which is called when data is sent to ‘/cable’. We take that data, find the corresponding note, and update it. Lastly, we broadcast the changes to everyone subscribed.

That’s it!

Sending and Receiving Data

On the front-end side, we need to do three things:

  1. Connect to ‘/cable’
  2. Subscribe to ‘NotesChannel’
  3. Send data to ‘NotesChannel’ when the user edits the textarea

We’ll start by importing the actioncable file we installed at the beginning of the tutorial:

// App.js, at the top
import ActionCable from 'actioncable'

Inside componentDidMount, we’ll connect to the ‘/cable’ endpoint via WebSockets:

const cable = ActionCable.createConsumer('ws://localhost:3001/cable')

Then, we create our subscription and set it as a class property:

this.sub = cable.subscriptions.create('NotesChannel', {
received: this.handleReceiveNewText
})

We subscribe to the channel, and set a callback for when we receive data from it. Let’s create that method:

handleReceiveNewText = ({ text }) => {
if (text !== this.state.text) {
this.setState({ text })
}
}

If the new text is different from our text, we set it to the state.

Lastly, let’s modify our handleChange method to send the changes to the back-end to be broadcasted:

handleChange = e => {
this.setState({ text: e.target.value })
this.sub.send({ text: e.target.value, id: 1 })
}

The final file:

Testing It Out

Open up your React app in two separate windows, and try typing. Both should change at the same time, like so:

In the terminal where your Rails server is running, you should see the output as ActionCable updates our note.

Next Steps

We’ve created a working real-time application in no time at all, which is neat. But there’s definitely room for improvement. Here’s some stretch goals to try out:

  1. Different routes for different notes on our React app
  2. Data sanitization and authorization for our Rails app
  3. Versioning the changes
  4. Batching updates so that we don’t send every single character over WebSockets
  5. Show who’s making the changes a la Google Docs (hard!)

You can follow me on Twitter here for more articles (including one with Rails and GraphQL coming up):

If you’re into the future of the web, check out the Progressive Web App newsletter:

If you liked this article, please recommend it or (even better) share it with someone who would find it cool (AKA your entire Twitter following and all your friends).

--

--

Scott Domes
Code == Life

Writer & teacher, currently focused on software (JavaScript, Rails & more). Author of Progressive Web Apps with React.