Deploying A Full-Stack App for the First Time (Vanilla Javascript & Rails API)  
Tags: deploy, fullstack, heroku, netlify
Published: 2021-04-24 18:31:20

As I went through the full-time Full-Stack Software Engineering program at Flatiron School, I built a handful of projects using different technologies and made sure to base them around my interests. Of all of my projects though, perhaps my favorite one has been my app “Ear Trainer” (if you have questions about `.bind`, you can read about my post from when I was first writing “Ear Trainer” [here](https://dev.to/maxjacobzander/in-a-bind-about-bind-12lb)!). “Ear Trainer” is an app for musicians to work on their abilities to hear and identify melodic intervals (the distance between two musical notes). It was super fun to build and it’s pretty fun to play with (if I do say so myself!).

Anyway, I knew that once I had graduated from Flatiron, I wanted one of my projects to be deploying "Ear Trainer" to the web for people to be able to use. What made it tricky however, was that it was a full-stack program, with a JavaScript/HTML/CSS front-end, and a Rails API back-end featuring a SQLite3 database. Ultimately, I got it, but not without a bunch of trial and error and in this post, I'm going to walk you through how I did it. And if you want to try out "Ear Trainer" for yourself, you can do so [here](https://ear-trainer.netlify.app/)!

<center>*Note: It may take a few seconds or a refresh or two to get it going and I'll explain why that is shortly!*</center>

-------

Upon doing some research about deploying apps, I came to realize that having two separate Github repos for my front-end and my back-end was going to mean two separate deployments. I had used [Netlify](https://www.netlify.com/) when I deployed my [portfolio](https://maxjacobzander.netlify.app/), but also knew that my back-end would be more suited to [Heroku](http://herokuapp.com/), so I signed up for an account and got to work.

First things first, I knew that if I wanted to deploy my back-end to Heroku, I was going to need to convert my SQLite3 database to a PostgreSQL database. Now, there are plenty of how-to's around the web about how to do that, but I'll give a quick run down.

## <center> To convert a SQLite database into a Postgres database:</center>

<b>Step 1.</b> Make sure that you have Postgres installed on your machine. Then,  replace the line in your `Gemfile` that says something along the lines of:
```
gem 'sqlite3', '~> 1.4'
```
<center> with </center>
```
gem 'pg'
```

<b>Step 2.</b> Run `bundle install` to make assure that the gem is installed into the package

<b>Step 3.</b> Next, go into your `config/database.yml` file. You will see something along the lines of:
```
# SQLite. Versions 3.8.0 and up are supported.
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
#
default: &default
  adapter: sqlite3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: db/test.sqlite3

production:
  <<: *default
  database: db/production.sqlite3
```

Now, we are going to replace this with some alternative code. I stole this from another blog at some point (so thank you to whomever I stole this code from!) and I'm going to break down a few parts of it for you so that you don't have some of the issues that I did.

So replace the above code with:
```
development:
  adapter: postgresql
  encoding: unicode
  database: app_name_development
  pool: 5
  username: yourusername
  password: yourpassword
  timeout: 5000
 
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: postgresql
  encoding: unicode
  database: app_name_test
  pool: 5
  username: yourusername
  password: yourpassword
  timeout: 5000
```

<b>*So let's clarify some of this here:*</b>

* First of all, your `database` is going to be your app name followed by either "development" or "test". (In this case, "Ear Trainer" becomes `ear_trainer_development` & `ear_trainer_test`.)

* You're also going to be asked to fill in your username and password. Now, what they're asking for in this particular case is your Postgres username and password. *Before you push to Github with your username and password written in this file, make sure you keep reading!*

<b>Step 4.</b> Run `rails db:create`, then `rails db:migrate`, then `rails db:seed`.

<b>Step 5.</b> You should be good to go! Check to see that your app is working!

### <center> A Quick Deviation into the Land of Environment Variables... </center>

Initially, I had put my Postgres username and password directly in my `database.yml` file, but I realized that doing so would make them vulnerable to leaks upon pushing my project to Github. So what's the solution? <b>Environment variables</b>.

If you are unfamiliar, environment variables will allow us to store our username and password in a separate file that we can then store in our `gitignore` so that it will run on your machine, but not push that sensitive information to Github! (More on how to do that below!)

*If you don't particularly care about this or don't plan on pushing your code to Github, you are welcome to skip this part and resume below!*

#### <center> To Add An Environment Variable In Ruby </center>
###### <center> <i>Also Applicable For Sinatra</i></center>

To get started, we need to run `gem install dotenv`. This will install the gem we need to make this happen.

Then, go back into your `Gemfile` and require the gem by adding add:
```
gem 'dotenv'
```

<i> (I don't know if this was actually the solution, but I had a little bit of difficulty getting things to work and after reading someone's suggestion on Stack Overflow, I moved the `dotenv` gem higher up in my `Gemfile` and it seemed to solve that issue. For reference, my `Gemfile` ended up looking like this:) </i>
```
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.1'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.3', '>= 6.0.3.4'
gem 'dotenv'
# Use sqlite3 as the database for Active Record
# gem 'sqlite3', '~> 1.4'
gem 'pg'
```
Once you've added the gem to your `Gemfile`, go into your `environment.rb` file and add the following line to the top:
```
require 'dotenv/load'
```
Now we're going to create our file.

In the top level of your system structure, create a file called `.env`. This file is going to contain your secret. Now, you can call your secret key whatever you want, since it's just a constant, but what you're going to do is name it, follow that with an `=` and then define it with your Postgres username and password. And that's how we create those variables! NB: **MAKE SURE YOU DO NOT ADD SPACES HERE!**

A hypothetical example of what this file may look like is:
```
ENV_USERNAME=thisismyusername
ENV_PASSWORD=thisismypassword
```

And, for the sake of what we're doing in this blog post, that's all that file needs!

Now, go back to your `config/database.yml` file and replace your username and password with the environment variables with the syntax:
```
 username: <%= ENV.fetch("ENV_USERNAME") %>
 password: <%= ENV.fetch("ENV_PASSWORD") %>
```

Check again to make sure that your program is still working and do a little happy dance to celebrate!

<img src="https://bestanimations.com/media/happy-dance/567876311happy-dance-animated-gif-image-44.gif" />

<center> <br>
Whew! Ok! Dance party's over. Let's get back to work! </center>
<br>
#### <center> To Keep Your `.env` File Safe </center>
So before we push to Github, we have to make sure that our `.env` file is listed in our `gitignore` so that we aren't pushing that sensitive information to the internet. Github has a wonderful resource for creating/adding to a `gitignore` file! You can find that (for just about any coding language!) [here](https://github.com/github/gitignore). Click on over to that, select your language and copy + paste whatever you need to your `gitignore` file. In our case, we are going to add our `.env` file by adding
```
# Used by dotenv library to load environment variables.
 .env
```
to our file. (Feel free to run `git status` to check and make sure that everything worked correctly and then push your work!)

Now we should be good to head to Heroku!

-----

## <center> Deploying The Back-End To Heroku </center>

So before you get started with this step, make sure that you make yourself an account with Heroku. Sign up and follow the documentation [here](https://devcenter.heroku.com/articles/heroku-cli) to get the CLI set up on your machine.

Now, there are multiple ways to proceed, but I like creating a new app from the Heroku website. You enter an app name, hit "Create App", and you're in business! I linked the Heroku-app to my Github repo for my back-end and thought I'd be done, but I had a few more snags that I had to solve.

First off, my first build attempts failed. Upon reading the build logs, I realized that my app was built with `Ruby 2.6.1`, which does not exist on the Heroku-20 stack (the current stack at the time of this writing). So if this is an issue you run into, this can be solved by setting the Heroku stack to one that *does* support `Ruby 2.6.1`. To do this, run:
```
heroku stack:set heroku-18
```
This changes the stack for the project and the next build will use Heroku-18 and (hopefully) succeed.

But when I first got the message that I had successfully deployed to Heroku, I was getting a `404` error. I realized that my problem was that I had totally forgotten about my routes! When I was running my rails server and going to localhost:3000, I hadn't set anything to the `/` route and needed to go to the proper route I *had* set to view what I needed. With the heroku-app page, it was the exact same thing! Make sure you are visiting the page with the proper route (ex. if you would go to https://localhost:3000/exampleroute, you will need to visit https://your-app-name.herokuapp.com/exampleroute).

But when I went to the proper route, there was *another* problem! I was getting an internal server error (500)! Now, if this is happening to you, you can run `heroku run rails console` (or `heroku run rails c`) if the logs aren't helping you diagnose the problem, but if you have been following along with this tutorial, you are probably hitting the same error (H10). Allow me to enlighten you: Because we put our login information into environment variables and put our `.env` file into our `gitignore`, Heroku does *not* have that information!

At this point, we need to provide that information to Heroku so that the information can be accessed. We can do that by running `heroku config:set YOURSECRETKEYFROMTHEENV=thepasswordthatyouset`(if we use the example from above, the entire command becomes:
`heroku config:set ENV_USERNAME=thisismyusername` and `heroku config:set ENV_PASSWORD=thisismypassword`.

Now Heroku has the login information it needs to access the information, but there's still something important to do: run `heroku run rake db:migrate` to migrate your database, followed by `heroku run rake db:seed` to seed it (if applicable). Now check out your deployed app (at https://your-app-name.herokuapp.com/exampleroute) and proceed to **HAPPY DANCE #2**!

<img src="https://i2.wp.com/media.giphy.com/media/w7mLEAMcpjrpe/giphy.gif?resize=372%2C372&ssl=1"/>

<center>
Ok! Stop dancing! We're almost there! </center>

-----

## <center> Deploying The Front-End To Netlify </center>

Alright, friend -- we're almost done. Just a few more steps and you'll be live!

First and foremost, make sure you have an account with [Netlify](https://www.netlify.com/). Netlify is super easy to use and this is going to be pretty simple!

But before we get there, we have one more important thing to do in our code. Now that your API lives somewhere on the internet, find your fetch request(s) in your front-end code and replace the location with your API.

To continue with our example links from before, we would move from something like:
```
class API {
    static addExamples(){
        fetch("http://localhost:3000/exampleroute")
        .then(resp => resp.json())
        ...
```
to something like:
```
class API {
    static addExamples(){
        fetch("https://your-app-name.herokuapp.com/exampleroute")
        .then(resp => resp.json())
        ...
```
Run your app with the new fetch request, make sure things work, and push to Github!

Now, before we start happy dancing again, let's just wrap this up, shall we?

Let's head back to Netlify. You're going to select "New site from Git" and choose your Git provider (I use/have been talking about GitHub, but you can also use GitLab or Bitbucket). Login to your account and pick a repository (in this case, your front-end repo!). Follow the prompts and deploy!

Guess what, my friend? You did it! Congratulations! <b>HAPPY DANCE #3</b>!!

<img src="https://media.giphy.com/media/igJK985xZj8Cqq0YOW/giphy.gif" />

<br><br>

*A final note: I mentioned at the beginning that if you wanted to try out [Ear Trainer](https://ear-trainer.netlify.app/), you might have wait about 30 seconds or refresh the page a few times. This is because the app uses what are called "free dynos", meaning that if no server requests happen for 30 minutes, the server will stop running. If someone tries to make a request to the server, it will wake itself back up and start running again, but it does take a second. A bit annoying, but hey -- it's free (and functional)!*