Image for post
Image for post
Heroku Platform

Deploying a Rails + React.js App to Heroku

Alejandro Sabogal
May 2, 2019 · 13 min read
  1. You used the rails new –api command to build the app in API mode (best practice in this case)
  2. You used create-react-app to build the React client
  3. Your Ruby version is 2.4.0 or above
  4. Your Rails version is 5.x
  5. You know what Heroku is and have set up an account and have their CLI installed
  6. You have Yarn or NPM installed (we’ll use Yarn in this article)

Changing the Rails Database

By default, Rails uses SQLite3 for its database, however, SQLite is not intended as a production-grade database. Heroku works with PostgreSQL, a more robust database. If you’re not familiar with PostgreSQL, I encourage you to research it; it’s really powerful and used by many applications.

group :development do
gem ‘sqlite3’
end
group :production do
gem ‘pg’
end
development:
adapter: postgresql
database: my_database_development
pool: 5
timeout: 5000
test:
adapter: postgresql
database: my_database_test
pool: 5
timeout: 5000
production:
adapter: postgresql
database: my_database_production
pool: 5
timeout: 5000

ActiveStorage Changes

Rails’ ActiveStorage allows you to attach files to ActiveRecord models. If you are using ActiveStorage to attach pictures, audio, or other files, you need to make some configuration changes before deployment. This is because Heroku uses an “ephemeral” disk that allows you to write files to it, however, those files won’t persist after the Heroku app is restarted.

Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
google:
service: GCS
project: your-app-name
credentials: <%= ENV['GOOGLE_APPLICATION_CREDENTIALS'] %>
bucket: your-app-name
google_dev:
service: GCS
project: your-app-name
credentials: <%= Rails.root.join("config/secrets/ your-app-name.json ") %>
bucket: your-app-name

Building the Production Client and Setting Up Rails for Deployment

Just as with a single React.js application, the client needs to be built to create a build directory that will hold the app’s production static files. Included in these files will be index.html, which will be served to visitors of the site. These files will be contained on the public folder of the Rails backend, which is what we want to deploy to Heroku. We can use Yarn (or NPM) to create the build and deploy scripts that will prepare our app for production.

{
"name": "my-awesome-package",
"version": "1.0.0",
"description": "The best package you will ever find.",
"main": "index.js",
"repository": {
"url": "https://github.com/yarnpkg/example-yarn-package",
"type": "git"
},
"author": "Yarn Contributor",
"license": "MIT"
}
"scripts": {
"build": "cd client && yarn install && yarn build && cd ..",
"deploy": "cp -a client/build/. public/",
"postinstall": "yarn build && yarn deploy && echo 'Client built!'"
},
yarn -v && npm -v && node -v
. . ."scripts": {
"build": "cd client && yarn install && yarn build && cd ..",
"deploy": "cp -a client/build/. public/",
"postinstall": "yarn build && yarn deploy && echo 'Client built!'"
},
"engines": {
"yarn": "1.21.1",
"npm": "6.11.3",
"node": "12.11.1"
},

Connecting the React Client to the Rails API

By default, the Rails server runs on port 3000. So does the client development build when ruining in your local server, i.e. when running yarn start or npm start.

{
"name": "client",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:3001",
"dependencies": {

. . .

}
const apiURL = 'http://localhost:3001'export const fetchWorkouts = () => {
let data = {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-type': 'application/json'
}
}
return dispatch => {
fetch(`${apiURL}/resources`, data)
.then(response => response.json())
.then(resources => dispatch({
type: 'FETCH_RESOURCES',
resources
}))
.catch(errors => errors)
}
}
//const apiURL = 'http://localhost:3001'export const fetchWorkouts = () => {
let data = {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-type': 'application/json'
}
}
return dispatch => {
fetch(`/resources`, data) //removed hard-coded path
.then(response => response.json())
.then(resources => dispatch({
type: 'FETCH_RESOURCES',
resources
}))
.catch(errors => errors)
}
}
class ApplicationController < ActionController::API  def fallback_index_html
render :file => 'public/index.html'
end

end
get '*path', to: "application#fallback_index_html", constraints: ->(request) do
!request.xhr? && request.format.html?
end

Deploying to Heroku

As a reminder, I’m assuming you have a Heroku account and have the Heroku CLI installed. If you haven’t, please go to https://www.heroku.com/, create an account and follow instructions on how to set up the CLI.

heroku config:set VARIABLE=VALUE


How I Get It…

JavaScript, React.js and Ruby on Rails Principles

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store