In this post, I’m going to write about my journey hosting an app on Heroku for the first time. I'll also be going over the steps on how to deploy, so please feel free to follow along. I struggled a lot, especially with deploying the backend, before I was finally able to get the app up and running, so I'll also talk about what kind of errors I ran into and hopefully, that will help anyone who is experiencing the same issues.
Table of Contents
Preparation Before Deploying
- I already had my Rails backend and React frontend in two separate GitHub repositories. This is important because the setup is different. If you have your app is set up where both the frontend and backend are combined into one, you can refer to this video
- My Rails API already has PostgreSQL as the database. If you don't have PostgreSQL set up, refer to Converting Rails from SQLite3 to PostgreSQL. For future reference, if you know that you will be creating an app that you plan to deploy to Heroku, run
rails new your-app-name-here --api --database=postgresql
so you don't have to switch from SQLite later. - I created a Heroku account. If you want to learn more about how the free option of Heroku works, read How FREE Heroku really works and how to get maximum from it?
- I installed Heroku's Command Line Inteface (CLI). This allows you to create and manage your Heroku apps from the terminal. I followed Heroku’s guide to set it up.
- Rails version 6.x
- Ruby version 2.6.1 and above
- Pushed all changes to Git before deploying
- I deployed from the master branch of my project
Setting up Heroku CLI
Since I use a Mac, I just opened up my terminal and ran
$ brew tap heroku/brew && brew install heroku
After you have installed the CLI, in your terminal, run
$ heroku login
Follow the prompts to log in to your Heroku account.
Deploying App to Heroku
Since I had my frontend and backend on separate repositories, I had to deploy the two separately to Heroku, so I created two separate Heroku apps. Using my app as an example, I named one Heroku app, the-next-episode-api
, for the Rails backend and the other as the-next-episode
for the React frontend. Note, the names of the apps don't have to match what you have for your GitHub repos.
Step 1: Setting up Rails API Backend
Make sure you have a root route/path in your config/routes.rb
and a static page that can be rendered when the app is first opened before React takes over. I didn't have one the first time I deployed my backend and I got a 404 error when I opened the Heroku app in the browser.
Heroku's guide goes over how to create a welcome page. The guide also explains that "Rails 6 no longer has a static index page in production by default. When you’re using a new app, there will not be a root page in production, so we need to create one."
From the Heroku guide:
We will first create a controller called welcome
for our home page to live:
rails generate controller welcome
Next we’ll add an index page:
In file app/views/welcome/index.html.erb
write:
<h2>Welcome to ...</h2>
Now we need to make Rails route to this action. We’ll edit config/routes.rb
to set the index page to our new method:
In file config/routes.rb
, on line 2 add:
root 'welcome#index'
You can verify that the page is there by running your server:
rails server
And visiting http://localhost:3000 in your browser. If you do not see the page, use the logs that are output to your server to debug.
Step 2: Deploying Rails API Backend
-
Navigate into the directory of your Rails backend
cd the-next-episode-api
-
Create Heroku app
heroku create the-next-episode-api
-
Initialize Heroku git remote
git remote add heroku git@heroku.com:the-next-episode-api.git
-
Add, commit, and push to your Heroku remote
git add . git commit -m "first Heroku deploy" git push heroku master
-
Migrate your database (don't need to run
heroku run rake db:create
)
heroku run rake db:migrate
-
(only if you need to seed database)
heroku run rake db:seed
If you have any keys you need to keep secret, like for JWT or external API, Heroku does not recognize ENV variables, so you need to configure those variables. There are two ways to do so:
Method 1: Can do so in Heroku CLI
heroku config:set API_KEY=put-your-api-key-here
Confirm variable is set, by running
heroku config
GITHUB_USERNAME: joesmith
API_KEY: your-api-key-here
OR
heroku config:get API_KEY
your-api-key-here
Method 2: Go to your app's settings on heroku.com and scroll down to Config Vars and add it there.
Errors I Encountered for Rails App and How to Debug
404 Error (page can't be found)
Solution: add root route to config/routes
I mentioned this before in the Setting up Rails API Backend section, but to fix this, I had to figure out why I was getting this error. To get a more detailed look at the error, I ran heroku logs
in the terminal and scrolled up until I saw an error that said ActionController::RoutingError (No route matches [GET] "/")
.
So after some research, I realized I was getting this error because I did not have a root route.
500 Error
Solution: Fix a couple of methods in my application_controller.rb
I was getting a 500 error because of the authorization/authentication methods I had in my application_controller. The methods were looking for a JSON Web Token or current_user
, but logging in and creating a user shouldn't require a JSON Web Token. That wouldn't make sense, so I added a check to check if a token exists (shouldn't exist if user is trying to log in/sign up),
def user_id
if decoded_token
decoded_token[0]["user_id"]
end
end
After updating these methods, I used Postman to check all my endpoints to make sure they are working like they're supposed to. Now, I was able to create a new user and log in without needing a token. I also checked the other endpoints that didn't need authorization and ones that did. They all worked!
So, I added, committed, pushed (git push heroku master
) the changes, and opened the Heroku app again. I went to Postman and replaced http://localhost:3000/api/v1/shows
with https://the-next-episode-api.herokuapp.com/api/v1/shows
and I got my JSON data. I checked all my other endpoints too just in case and everything worked, so I moved onto deploying my React frontend.
Step 3: Deploy React Frontend
1. If using React Router, create file in project's root directory named static.json
that has the following code:
{ "root": "build/", "routes": { "/**": "index.html" } }
In this stack overflow post, the second answer explains why we need this file,
"The public static directory is mapped to the / endpoint, and visiting this endpoint from a browser will download the index.html webpage. This webpage in turn loads the React components. And because React Browser Router is a React component, the routes are loaded dynamically after visiting the / endpoint. In other words, before the index.html webpage is loaded all our React Browser Router routes will result in 404 errors on Heroku. To resolve this issue, a static.json file can be used to map any endpoints with the following pattern /** to the index.html file, which in turn will load React Browser Router and correctly load the react components for that route."
2. Update all the URLs in your fetch requests or any other reference to your Rails API
Replace all http://localhost:3000
with the URL of your deployed backend, https://your-app-name-here-api.herokuapp.com
.
If you have your routes namespaced, like http://localhost:3000/api/v1/...
, replace ONLY the http://localhost:3000
part. Leave this part /api/v1/...
. So, it should look something like
https://your-app-name-here-api.herokuapp.com/api/v1/...
3. Create Heroku app set to create-react-app
buildpack:
heroku create your-app-name-here --buildpack https://github.com/mars/create-react-app-buildpack.git
Without the buildpack, Heroku will deploy the development build (which is slow) of your React app instead of the optimized production build.
4. Initialize Heroku remote:
git remote add heroku git@heroku.com:your-app-name-here.git
5. Add, commit, and push to Heroku remote:
git add .
git commit -m "First Heroku deploy with create-react-app"
git push heroku master
6. Open app and you're done!
heroku open
This is my app, The Next Episode if you want to check it out.
Thanks for reading and hope this helped!
Top comments (2)
Thanks Cindy! As a fellow Flatiron grad, this is super helpful
Super helpful! Thanks for writing this up. I am deploying a couple things and this helps, a ton. PS- I love your Next Episode app! Great idea, and I love the look of it.