DEV Community

Max
Max

Posted on

ActionCable and React for Beginners

Introduction

Everyone is familiar with HTTP, whether they know it or not. As web developers, we understand that it is an internet protocol used to send and receive requests from a client to a server. A typical exchange looks something like this :

Image description

But sometimes, we want real-time interaction with others. For example, users on Discord or Slack don't manually refresh their applications to get new messages, they are simply received. To facilitate this need for real-time updates, we can use WebSockets.

Put simply, WebSocket is an alternative internet protocol that allows for dynamic two-way communication between a client and server. Instead of a user requesting new information (like refreshing a page to load new posts), the user will receive data as it is broadcasted.

In this post, I will be walking you through how to set up a basic Chatroom using Rails ActionCable and a React Frontend.

Configuration

First we'll run through the basic application configuration.

Create a new Rails API in a directory.
rails new chat_app --api

Navigate to the newly created directory and create your React Client

#/chat_app
npx create-react-app client
Enter fullscreen mode Exit fullscreen mode

Install @rails/actioncable to your React client

#/chat_app 
npm i @rails/actioncable --prefix client
Enter fullscreen mode Exit fullscreen mode

In the Gemfile, uncomment "rack-cors"

Image description

This post won't go into deployment, but if you plan on doing so, uncomment "redis" and add the "pg" PostgreSQL gems and change your database adapters as required. This example won't go into deployment so you can leave the "sqlite3" gem and the default settings.

Uncomment this middleware and change origins to "*" for development purposes. Note you would have to change the origin to your application domain if you were deploying.

Image description

Finally, install your gems and client dependencies.

#/chat_app
bundle install
npm install --prefix client
Enter fullscreen mode Exit fullscreen mode

Rails

To setup a WebSocket connection, we need to configure both our front and backend to create a 'handshake' or connection. We'll start with establishing the backend.

In Rails, let's generate a scaffold for a Message model. We'll keep things simple and only have a content attribute for our model.

rails g scaffold Message content
#Don't forget to migrate
rails db:migrate
Enter fullscreen mode Exit fullscreen mode

Moving to /app/config/routes.rb, we can see that Rails has generated resources for our messages already. But we will also need to declare the endpoint for our ActionCable WebSocket server.

Image description

We have a model, it's controller and a server endpoint 'localhost:3000/cable'. Next we need something manage our connections and requests: a Channel.

Like the controller in MVC, a channel acts as a unit that takes requests and processes those request with respect to the defined actions it receives.

rails g channel Chat
Enter fullscreen mode Exit fullscreen mode

Image description

In app/channels/chat_channel.rb, you will see our ChatChannel with two default actions: subscribed and unsubscribed. When a user attempts to make a WebSocket connection with our server, it will state what kind of request it is and to what channel. We could do different things to process a request such as adding authentication tokens, but we'll focus on the main function of the channel: streaming.

You can declare a stream from either a specific string, a dynamic interpolated string, or even from an instance of a model. In all cases, the user requests a subscription the ChatChannel and the ChatChannel will in return establish a connection and stream from the specified source.

Image description

This project will proceed using the stream_from "chat" configuration so we'll comment out the other examples.

Now that we've established a way for users to connect to our WebSocket server, we need to define when our server actually broadcasts information to our users.

In general, we're going to want to broadcast data to our channel when users create new messages.

Image description

ActionCable.server.broadcast("chat", @message) tells our server to broadcast our @message to the stream "chat". If you broadcast from a model, you will need to use different syntax, refer to https://guides.rubyonrails.org/action_cable_overview.html.

React

For brevity, I will only cover setting up WebSockets on the frontend.

In /app/client/src create a new file cable.js. This will manage the creation of our client-side 'consumer'.

Image description

Note that the protocol of our URL is now 'ws' not 'http'. This will tell our server that the user is attempting to establish a WebSocket.

In App.js, we want the client to make a subscription request to our ChatChannel. Thanks to @rails/actioncable we can also describe what we want to happen when we are connected, and when we receive data (if our connection is established).

Image description

From our backend we can see if a request is successful by viewing our terminal.

Image description

When we make a post request to our backend, our Messages Controller broadcasts our message to the "chat" stream.

Image description

When it broadcasts, our clients are set up to setMessages using that received information.

You can view realtime updates by opening the application an in incognito window. You will notice that both will update whenever the other sends a message.

Conclusion

WebSocket is a great tool to allow for interactive communication for users. It was difficult for me at first to really get a grasp on some of the examples out there, so I hope this provides a very basic illustration of how to set up ActionCable with a React Frontend application. I didn't cover management of connection requests or illustrate the use of multiple streams, but I think this shows the very basics on how to get a chatroom going. Let me know if there's anything I missed or anything you'd want me to cover!

Top comments (0)