Creating a Ruby CLI Journal Application, Part 1: Models, Relationships, and Creating a Database

Allene Norton
8 min readOct 23, 2020

For our Module 1 project at Flatiron School, we were tasked with creating a CLI application using object-oriented programming in Ruby. For those unfamiliar with programmer-speak, a CLI application is a command-line interface application. This means that all user interaction with the app is done via the command-line in the user’s terminal, and all interactions consist of either text input or keystrokes; there is no GUI (graphical user interface) with interactive visual components that allow the user to click on icons or other graphics to navigate and interact with the application.

The idea of a text and keystroke based application was exciting to me, as the examples we were shown reminded me of 80s/early 90s turn-based RPG games. Coming up with the idea for our project, however, was difficult. The guidelines for the project required the following (and more):

  • A minimum of four user stories to help explain how a user will interact with the application
  • At minimum 3 models, with at least one many-to-many relationship
  • Accessing and interacting with an API
  • Accessing a Sqlite3 database using ActiveRecord
  • Methods that answer interesting questions about the data

Ultimately, we decided that a journaling application would best suit the project requirements, and so we began our quest to satisfy the requirements, as well as our own desires regarding styling and user interaction. In this blog, I’ll go over how we tackled each part of the creation process.

User Stories

Coming up with the user stories was perhaps the easiest part of the project. We knew that we needed to have working parts that performed at least some of the CRUD actions, and we came up with the following:

  • as a user I want to be able to create a journal entry
  • as a user I want to be able to save a journal entry
  • as a user I want to be able to delete a journal entry
  • as a user I want to be able to associate a journal entry with an emotion
  • as a user I want to be able to see a list of my journal entries and emotions
  • as a user I want to be able to lookup my journal entries by emotion

Some of these user stories were written before we began the project, and others came to light in the process of creating the application. Associating entries with emotions involved using an API we found which analyzes the text of a journal entry, but I will get to that in a little while. In order to begin the project, we first needed to decide on what our models would be and their relationships.

Models

Models, in object-oriented programming, are more or less classes that instances (a.k.a. objects) belong to. These objects will act according to methods defined in the model classes.

You can think of classes in object-oriented programming as a class (or type) of something, anything really, that has a defined set of characteristics to which an object of that class adheres. For example, umbrellas are a class of real-world objects. All umbrellas open, close, and prevent (in most cases) the user from getting wet. The umbrella I keep in my car is an instance of the class of Umbrella; it does all of the things that objects that belong to the class of Umbrella should do, and it also has its own characteristics (size, color, etc.) that are unique to that instance of an umbrella.

So, what are the models for a journaling application? Well, for one, we know there needs to be someone writing in the journal; for our purposes we will call them a user.

What does the user do? Our first user story states that a user should be able to create a journal entry. Therefore we know that we need to have both a journal model and an entry model. That gave us the 3 models we needed to create for the project, and our next step was to determine the relationships between those models.

Relationships

In ActiveRecord, models have relationships to each other. I won’t go into all of the possibilities that ActiveRecord gives us, but I’ll list here some of that the relationships that ActiveRecord supports:

  • belongs to
  • has many
  • has many, through

Coding these relationships into our models gives us the support from ActiveRecord that allows our models to interact with each other.

example of user model relationships
example of User model relationships
example of entry model relationships
example of Entry model relationships

This makes sense if you think about it in a real-world setting. A person can have many journals, but their relationship to those journals is really a result of their writing entries into those journals. Thus, a person really has many journals through the entries they create. A journal could also technically have many users (think of perhaps a guest logbook at an Airbnb), and they have many users through the entries they write.

Once we determined the relationships between our models, our next step was to create our database.

Creating a Database

With the powers of Sqlite3 and ActiveRecord combined, we can use the relationships defined in the last section to create a database of users, entries, and journals that will power the bulk of the functionality of our app. When you create an instance of the user class, for example, the characteristics of that user will be saved in the database.

Determining the characteristics, or attributes, of an object is the first step in creating a database. What attributes should a user have? A journal? An entry?

For our purposes, the only attribute we gave to a journal was a name, and the same went for user. The attributes for entries is where things get interesting, and also where the magic of ActiveRecord begins to apply.

Journal entries typically consist of 2 parts in the real-world: the text of the entry, and a date it was written on. We also added an “emotion” attribute, that would store the result of the emotional analysis API. Later on in development, we also added the attribute of “journal name”, that would store the name of the journal the entry was created in, so that we could implement a “list entries by journal name” function in the app. The other two attributes are where we added the relationships available to the Entry model: “journal_id” and “user_id”. These attributes are (in addition to defining them in the models as we did above) how ActiveRecord knows which journal and user the entry is associated with.

We use Rake and ActiveRecord to create tables for our database based on our models. ActiveRecord has a set of conventions for naming models and tables. The model is always a singular and capitalized, whereas the table is lowercase and plural. So, our User model becomes a “users” table, and so on with the other models, and that is how ActiveRecord knows to associate those models with those tables.

Creating and Executing Migrations

In order to create a table, we first have to create a migration. Migrations are files with instructions for creating or augmenting tables in the database. You can do this directly from the command-line by typing “rake db:create_migration *plural lowercase model name* *attribute:datatype*”. In our case, it looked like this:

sample migration creation

This created a migration file that looked like this:

sample entries migration file

However, the table is not created with this step. In order to access the table in our database, we have to migrate the migration file to the database. All you need to do for this next step is to run the command “rake db:migrate”… and voila! The table is inserted into the database, and in our schema for the database, we can now see that the table is there.

sample schema, you can see all of the tables created during migration

Seeding the database

Now that we have our models, relationships, and tables, we need to test if the relationships actually work. The best way to do this in the initial stages of the project is to create seeds in the seeds.rb file that is created upon creation of a database using Sqlite3/ActiveRecord.

In the seeds.rb file, we created instances of the User and Journal class, set those to variables, and then created instances of the Entry class supplying the instances of User and Journal we created prior.

sample seeds.rb

The variables we set our instances of User and Journal to are passed into the entries we create, that way we are associating each entry to a user and a journal. Note that we don’t need to do anything with the id of the user or journal, ActiveRecord automatically knows that “user: jane” should put the id of the user instance stored in the “jane” variable into the “user_id” column of our entries table. Pretty neat, in my opinion! Run “rake db:seed” to seed your creations in the database.

Testing Relationships

Now that we have some seeds to play around with, we can type “rake console” and use that to test our relationships. You can type “Entry.all” to see a list of all entries. Set “Entry.last” to a variable (i.e. “last_entry = Entry.last”), then see what user is associated with that entry (i.e. “last_entry.user”). If everything is working properly, that command should return the instance of the User class associated with that last entry. You can run commands in a similar fashion to test all of your relationships.

Conclusion

Sweet! We’ve just created models, defined their relationships, written migrations, and seeded our database. Next, we have to talk about how to control all of the interactions between our models, and how to write methods to give our app some functionality. Check out part II of this mini-series here for more information on how to finish creating the application. Keep in mind that while I am writing this instructional series based on the journaling domain we chose for our project, you could use any domain for your models, whether it be recipes, sports, you name it! Regardless of which domain you model, the important takeaways so far should be:

  • understanding what you want the user to be able to do with your app
  • determining which models are appropriate
  • determining the relationships between your models
  • creating migration files, running migrations to create tables in a database, and seeding the database with instances of your models

That’s all I have for now, see you in part two!

--

--

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