Creating a Ruby CLI Journal Application, Part 2: Methods, Using an API, and Credentials

Allene Norton
7 min readOct 23, 2020

Read part one of this series here

We left off having just created our database, so where do we go from here? For me, as a new coder with very little experience, I still wasn’t entirely sure of how to make a program actually run, despite having a beginner’s understanding at that point of OOP (object-oriented programming) and the way that models interact through their relationships. It took a bit of research and studying other Ruby CLI applications to gain the understanding that functions are what make the program, well, function.

“A function is a block of organized, reusable code that is used to perform a single, related action…Different programming languages name them differently, for example, functions, methods, sub-routines, procedures, etc.” In Ruby, functions are referred to as methods. We use these methods to instruct our program to do a variety of things. Displaying content on the screen, timing the flow of the application, manipulating data, and many other actions are all controlled by methods.

Methods

The first method in our CLI journal project displays a welcome message, prompts the user to input their name, and uses conditional logic to either create or find a user by their name in our database. Once those steps have been completed by the program, the method calls and performs another method in the program, and so on and so forth. This is what creates the flow of the application. Now, I won’t get into all of the methods we used, but I will walk through the first few to explain how they work.

first method in Journalwave

Here we have a method that defines instance variables and uses built-in Ruby and ActiveRecord functions to act upon them. The @prompt variable creates a new instance of TTY Prompt, a gem for prompting users for input that I’ll explain in the next section. The @newline variable is implemented to make it easy to break up text as the application flows. The application asks the user to provide their name, and then gets the user input and removes (or chomps) any whitespace. Next, we use some ActiveRecord magic to query our database and find or create a user instance with the name given by the user. Then, conditional logic is used to render either a “welcome” or “welcome back” message, and then the program calls new methods, continuing the application flow. The ‘ask_exercise’ method asks the user if they want to do a breathing exercise, a fun little extra we included in the program that I’ll discuss in the next section. Let’s move on to the menu.

menu method for Journalwave

Using this method, we display a menu with many options for the user. Each variable in the case block references another method defined elsewhere in our code, called when the user selects the related option.

At this point it is starting to become clear how Ruby uses methods to control the functionality of the application. Methods perform actions and call other methods, and those methods perform actions and call other methods, and so on and so forth. The possibilities are seemingly limitless!

The methods we used in our journal application allow the user to interact further with our database. Most of the methods referenced in our menu perform CRUD actions that allow the user to Create, Read, Update, or Delete records in our database. Let’s take a closer look at one of those methods.

This method searches our database for entries that match the emotion chosen by the user. We assign the choices to an array and call a multi-select prompt with those options. We then use ActiveRecord to find all entries where the emotion matches the selection, and define the data we want displayed to the user. The ‘tp’ calls another gem, table_print, that displays the returned data in a well-structured table format. The last line calls another method that gives the user some options for what to do next. Hopefully I have demonstrated clearly how programmers use methods to define the functionality of a program!

API

The project requirements stated that we must use an API, or application programming interface. Put into extremely simple terms, an API is basically a set of rules for how an application can access a set of data. Now, many if not most APIs are built to return JSON datasets. However, we chose a slightly unorthodox API, Emotion Analysis by twinword. This API allowed us to send input from the user and receive an analysis of the primary emotion of that text. This is how we are able to analyze the emotions of our users’ journal entries.

Figuring out how to make a call to an API in the third week of our program was definitely tough. We needed to implement something that allowed us to send HTTP requests receive a response containing the desired data. For this project we used the built-in Ruby client Net::HTTP, but there are quite a few gems that provide this service as well. We had to make the text URI-friendly, because this API requires you to send the text to be analyzed in a URL. One of the more fun parts of this project for me was writing code that could make our user input URI-friendly, although looking back I could likely have found a gem to do that for me.

Once we had everything ready for our API request, we needed to provide some credentials in the headers of the request. Specifically, we needed to supply some information about the resource we were requesting (the host), as well as information about our application (the client). If the API receives our request with the correct headers, it returns a success status and the data we desire, and conversely a failure status if the right information isn’t sent. The host information is available from the API, and the client information is stored in a key provided to you from the API to verify that the client is who it says it is. Once everything is sent and received from the API, we then have access to the data, in our case the emotion, and we can use it however we like in our application.

Journalwave API function call

This code may not be self-explanatory if you are a beginner like I was when I made this project, but the basics of this function are as such:

Convert the input to a URI-friendly format and interpolate into URL

Define the parameters of the HTTP request to the API: Create a new instance of Net::HTTP, define some SSL settings, define the type of request and headers, call the API using http.request and set response to a variable, parse the response, and access the data from the response.

That’s a lot of stuff going on in that small bit of code! But, it all boils down to sending a request, receiving a response, and doing something with that response.

Credentials

I want to briefly touch on encrypting credentials here. If you notice in the above code, our API key is written as ENV[‘EMOTION_API_KEY], when in fact the key itself is a long string of seemingly random alpha-numeric characters that look something like this: ‘aRbf87fn93n45DD487n94Utd’. However, it is unwise (and, in cases where you are paying for your API calls, EXTREMELY unwise) to have your raw API key in your code. If you push your repo to GitHub without encrypting your key, anyone can grab your key and use it as much as they want. I have heard rumors of students getting stuck with thousands of dollars of payments because they didn’t encrypt their data! We need to hide the key somewhere our application can access it without exposing our data.

For this project, I used the dotenv gem, since this is not a Rails application and doesn’t have access to any built-in methods for encryption. Using the gem is pretty simple, once it has been installed you simply store your actual key in a .env file and access it in your code as ENV[‘YOUR_API_KEY’]. Make sure to add the .env file (which should be placed in the root directory of your app) to the .gitignore file also in your root directory if initialized with Git, otherwise the data will still be exposed when you push your repo.

Conclusion

Our CLI Ruby application is almost finished! We’ve gone over the setup in part one, and the implementation here in part two. To finish this mini-series, I’m going to talk about what I did to make this app look rad and run less like straight-up terminal text, and more like an actual program. You can check out part three of this series here.

--

--

Allene Norton

Full stack developer and Flatiron graduate who recently made the jump from a career as a professional musician and audio engineer | Austin, TX