How To Add React to Rails Apps v2
In our previous article, we discussed how NextLink Labs uses the Rabl gem to send data from our Rails APIs. This article will demonstrate the packages that we add to the React front-end to fetch and display that data.
Note: You’ll find more info on advanced Rabl tips and techniques here.
Set Up Your Rails REST API
First, we need to make a few small adjustments on the Rails side.
With our approach, we won’t be using any .erb files at all. Having them around can occasionally cause headaches. So if your users folder has an index.html.erb or a show.html.erb file, go ahead and delete them.
We also need to install the cors gem. Without it, our Rails REST API will not allow any other apps to access its data because of cross-site security concerns. Gemfile
Gem “rack-cors”
Install the gems, then start your Rails server.Terminal
bundle install
rails s
Include localhost in the list of source sites that are allowed to access the API. config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "http://localhost:3001"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
Build a React App
Now we’re ready to build our React app. Some tutorials will have you keep your React code in the same folder as your Rails code. At NextLink, we prefer to use two separate repositories to keep everything better organized. To follow our approach, you’ll need to open a second IDE window and a separate folder.
First, spawn a new React app.Terminal
npx create-react-app rabl-react-demo
After it finishes creating your files, switch into that directory. Terminal
cd rabl-react-demo
Then add the axios package.
Note: If you haven’t yet installed yarn, you’ll need to do that at this point. Alternatively, everything should work using npm as your package manager, but the author has not tested that. The remainder of this article will move forward using yarn as the package manager.Terminal
yarn add axios
By default, your React app will be set to run on port 3000. This is a problem because that’s the same port where our Rails app is running.
Change the port for the React app in the scripts section of the package.json file. In this example, we’ll go with Port 3001. (That’s also the port that we used in the CORS configuration of our Rails app.)package.json
"scripts": {
"start": "PORT=3001 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Customize Your React Front-End
You could make your front-end as fancy and attractive as you’d like, with multiple routes and components pulled from various files. But for this brief demonstration, we’re just going to add a few things to the standard App.js file that comes with a create-react-app build.
At the top, we need to import axios and also React itself. This implementation will leverage useEffect and useState, so let’s import those as well.src/App.js
import logo from "./logo.svg";
import "./App.css";
import Axios from "axios";
import React, { useEffect, useState } from "react";
Inside the function block, establish a users state.src/App.js
function App() {
const [users, setUsers] = useState([]);
Also in the function block, we need an API function, a function to call it, and a useEffect to call that. const API = Axios.create({
baseURL: "http://localhost:3000/users",
timeout: 120000,
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
const fetchUsers = async () => {
const response = await API();
setUsers(response?.data?.result);
};
useEffect(() => {
fetchUsers();
}, []);
And finally, we display our json-called users object on the screen. Somewhere inside the return block, add: <p>{JSON.stringify(users)}</p>
At this point, the complete App.js file looks like this:src/App.js
import logo from "./logo.svg";
import "./App.css";
import Axios from "axios";
import React, { useEffect, useState } from "react";
function App() {
const [users, setUsers] = useState([]);
const API = Axios.create({
baseURL: "http://localhost:3000/users",
timeout: 120000,
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
const fetchUsers = async () => {
const response = await API();
setUsers(response?.data?.result);
};
useEffect(() => {
fetchUsers();
}, []);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<p>{JSON.stringify(users)}</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Start the React app.Terminal
yarn start
When you browse to http://localhost:3001/, you should see:
The users from our Rails database are there, in a slightly more user-friendly way.
Let’s polish it up a bit.
Replace this line:
<p>{JSON.stringify(users)}</p>
with: {users?.map((user) => (
<>
{user.last_name}, {user.first_name}
<br />
</>
))}
So our App.js file now looks like this:src/App.js
import logo from "./logo.svg";
import "./App.css";
import Axios from "axios";
import React, { useEffect, useState } from "react";
function App() {
const [users, setUsers] = useState([]);
const API = Axios.create({
baseURL: "http://localhost:3000/users",
timeout: 120000,
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
const fetchUsers = async () => {
const response = await API();
setUsers(response?.data?.result);
};
useEffect(() => {
fetchUsers();
}, []);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
{users?.map((user) => (
<>
{user.last_name}, {user.first_name}
<br />
</>
))}
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
And in the browser we see:
From here, we’ll leave it to you to use your React skills to dress this up. Hopefully you can start to picture how you could organize the JSON object from your API into tables, lists, buttons, links, etc.
To finish the series, learn how to use nodes and loops on your Rabl file to send more detailed and complex information.
Read Next: Advanced Rabl Tips and Techniques
Questions About Rails APIs
If you’re working with technical debt, NextLink Labs can help with any questions about Rails APIs or API design in general.
See how our Custom Software Development solution can benefit your team.