Launch App — JavaScript + Rails API

Launch Project Management App

Launch is a Project Management single-page application where users can build teams, keep track of assigned tasks, and communicate with other team members — all of which contribute to the eventual goal of getting ready to launch the project!

Flatiron School’s Phase 4 section kicks off with the introduction of JavaScript. Although I’ve attempted to teach myself the basics of JavaScript in the past, I have never used it in the way that I have for this latest project. With the introduction of Object Orientation way back in Phase 1, we learned that you can create Class Objects to allow your application models to easily interact with each other in your program. The same concept also applies to JavaScript, and it has literally changed everything I knew and understood about this language. But before we jump into that, let’s take a quick look at our backend server, which utilizes the incredible power of Ruby on Rails.

Rails as an API Backend Server

As we’ve learned from Phase 3, Rails has the ability to completely handle the functionality of a web application, including both frontend and backend requirements. For this project, however, we’ll be using Rails to handle just the backend portion, which allows us to use JavaScript to take care of our frontend needs. In order to use Rails as an API, we can attach the “api” parameter when creating a new rails application:

rails new project-name --api

By including this parameter, Rails generates the usual MVC (Model-View-Controller) structure, with all required database and configuration files, as well as the integration of ActiveRecord’s beautiful macro methods. What it omits are the files and folders that normally interact with our ‘views’, including ERB files, helper methods, etc. Additionally, since our data will be accessed from a source that exists outside the bounds of our Rails server, we’ll need a different approach when rendering our data in our controllers.

We can set up our Rails server as usual — creating all the necessary models, building our database, defining our associations, etc. In our controllers, however, rather than saving our data in instance variables and implicitly rendering them to our local ERB files, we can instead render them to JSON format, exposing the data in our application routes so that other programs (like our JavaScript frontend application) can have access to them. To do this, we can explicitly tell our controller actions to render our data via the following code (assuming we are in the “User” controller):

def index
user = User.all
render json: user
end

When visiting this route in a browser, we see that it returns something like this:

Note: JSON is data that is presented in JavaScript Object Notation (hence its acronym). A JavaScript Object is much like a Hash in Ruby, where data is stored as Key/Value Pairs, and it turns out to be a very efficient way of sending and receiving data, provided we are parsing the data correctly when it reaches its destination. We’ll touch more on this a bit later in the article.

Great! Now that we have our backend server all set up, let’s take a look at how we can retrieve data from our frontend JavaScript application, as well as how to send data back to the server.

JavaScript Fetch Method

JavaScript provides a simple way of obtaining data from an API source , which is accomplished by using its built-in “fetch” method. Here is the basic structure for a fetch request to retrieve User data from my Rails API running on localhost:3000:

let baseUrl = "http://localhost:3000"
let route = "/users"
fetch(baseUrl + route)
.then(response => response.json())
.then(data => handleData)
.catch(error => console.log(error))
let handleData = data => {
// Code to handle json data goes here
}

You can substitute “baseUrl + route” with any available API endpoint in order to get the data from that particular source. Note that some endpoints may require you to provide some sort of authentication (like an API Key) in order to access their data, but we won’t be going over that in this article. Assuming the endpoint responds with a 200 OK response, the data is then converted from a String Object to a JavaScript Object via the “.json()” method. With the data properly parsed, we can now handle this data as a regular object inside our javascript program.

The fetch method is incredibly useful for sending data to a server as well. Remember that our Rails server also has routes that are associated with the “create” and “update” actions in its controllers, which listens for “POST” and “PATCH” requests, respectively. In order to send a POST request to our server, we can pass a Configuration Object to the fetch() method, which looks something like this:

let userInfo = {
// User Info Data
}
let configObj = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify(userInfo)
}
fetch(baseUrl + route, configObj)
.then(response => response.json())
.then(data => handlePostData)

Notice how we pass the “configObj” as a second argument in the fetch() method, which the API server uses so that it knows how to handle the request. This means that if we want to target the Update or Delete action, we can instead define the ‘method’ parameter as ‘PATCH’ or ‘DELETE’ , respectively.

The way I see it, the fetch() method acts as the liaison between the backend (Server) and frontend (Client), allowing for both sides to communicate with each other and send/update data back and forth. In terms of our MVC structure, our JavaScript frontend has taken the role of “V” (or the View), and the fetch() request allows our “V” to interact with our “C” (or the Controller). The overall MVC structure remains in tact, but we now have more options on how to present our data to our users, which I think is incredibly versatile and just absolutely brilliant.

Defining Class Objects in JavaScript

One of the great things about Object-Oriented Design is the ability to keep our code DRY (Don’t-Repeat-Yourself) and organized. In order to get the most use of our JS objects, I’ve created 2 classes for each model: one to handle the object’s attributes & functionality, and the other to handle its interactions with the backend server. Here’s a quick look at my ‘user.js’ and ‘userApi.js’ files:

User and UserApi Classes

Since this was my first time really using Object-Oriented Design for JavaScript, I took some time to mess around with different ways of accomplishing the same thing. It took me several attempts to finally find a clean way of structuring my classes and figuring out exactly how to efficiently append/remove data from the DOM (Document Object Model). I decided to maintain some sort of consistency for all of my JS Objects by structuring each class as follows:

class MyClass {
// *** Define the ALL variable
static all = []

// *** Define the Constructor
constructor({id, thing_id}) {
this.id = id
this.thingId = thing_id
MyClass.all.push(this)
}
// *** Define Associations
...
// *** Define Main Functions
...
// *** Define Event Handling Functions
...
// *** Define a RENDER function
static render() {
content.innerHTML = `<div>Initial Render for this class</div>`

// *** Initial DOM Manipulations
...
// *** Define Initial Event Listeners
...
}
}

The render() function is the first function that is called when accessing the defined class, which renders its initial content to the browser, as well as all event listeners that are attached to any DOM objects that this class uses.

When it comes to appending elements to the DOM, I found myself switching between the “.append()” function and the “innerHTML=” approach. Eventually, I settled on the latter. I didn’t notice any striking benefits to choosing one over the other, at least in the context of this project, but I did feel more comfortable about choosing just one approach in order to maintain some consistency in my code.

Conclusion

Launch was a really fun project to build as it gave me a chance to play around with JavaScript’s various Event Listeners. At first, I did find it a bit difficult to settle on a particular flow when it came to structuring my classes, but the process definitely improved once I decided to stick to some form of consistency. Ruby on Rails has impressed me from the moment I started using it in Phase 3 of this program, and it continues to prove its incredible value as a permanent staple in my Software Development Toolkit.

Phase 5 is just around the corner, and I feel excited to have made it this far with my Flatiron Cohort. I’m extremely grateful for this experience as I now feel more confident than ever to finally call myself a Software Engineer. Although this journey is coming to an end, our new careers are only just beginning, so let’s finish strong! Final Phase, here we come!

Launch App ~ JavaScript + Rails API

If you’re interested in viewing or contributing to this project, check out the Github Repo here. Additionally, the video below provides a walkthrough demo of the application:

Software Engineer | React | Redux | Ruby | Rails

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