DEV Community

loading...
Cover image for Deploying A Full-Stack App for the First Time (Vanilla Javascript & Rails API)



Deploying A Full-Stack App for the First Time (Vanilla Javascript & Rails API)



Max Zander
Professional Opera Singer turned Full-Stack Developer
Updated on ・9 min read

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!). “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!

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

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 when I deployed my portfolio, but also knew that my back-end would be more suited to Heroku, 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.

To convert a SQLite database into a Postgres database:

Step 1. 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'
Enter fullscreen mode Exit fullscreen mode
with

gem 'pg'
Enter fullscreen mode Exit fullscreen mode

Step 2. Run bundle install to make assure that the gem is installed into the package

Step 3. 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

So let's clarify some of this here:

  • 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!

Step 4. Run rails db:create, then rails db:migrate, then rails db:seed.

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

A Quick Deviation into the Land of Environment Variables...

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? Environment variables.

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!

To Add An Environment Variable In Ruby

Also Applicable For Sinatra

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'
Enter fullscreen mode Exit fullscreen mode

(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:)

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'
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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") %>
Enter fullscreen mode Exit fullscreen mode

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



Whew! Ok! Dance party's over. Let's get back to work!


To Keep Your .env File Safe

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. 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
Enter fullscreen mode Exit fullscreen mode

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!


Deploying The Back-End To Heroku

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 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
Enter fullscreen mode Exit fullscreen mode

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!


Ok! Stop dancing! We're almost there!

Deploying The Front-End To Netlify

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. 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())
        ...
Enter fullscreen mode Exit fullscreen mode

to something like:

class API {
    static addExamples(){
        fetch("https://your-app-name.herokuapp.com/exampleroute")
        .then(resp => resp.json())
        ...
Enter fullscreen mode Exit fullscreen mode

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! HAPPY DANCE #3!!

A final note: I mentioned at the beginning that if you wanted to try out Ear Trainer, 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)!

Discussion (0)