Debugging Has Many, Through Relationships in Ruby on Rails

Working with associations was the most difficult part of building Central Perk, my Ruby on Rails application. has_many and belongs_to relationships made sense, but the addition to many-to-many—has_many through—relationships are where it got weird. I ran into several issues while building my app and here’s how I solved them.

For my app, I planned on three models. Users (baristas), orders and menu items (products). The relationship would like this:

Sketch outlining the User <–| Order |–> Item relationship

With those models, programmatically, that I wanted to be able to do the following:

  • Create a new order and automatically associate it with a user. shannon.orders.create
  • Be able to see all orders that belong to a user. shannon.orders
  • See all menu_items (products) in a specific order. order.menu_items

Everything with setting up my models seemed to be working fine up until the last part. Currently, an Order with an attribute of :menu_items could only have one value. Meaning, just one MenuItem per Order. Can you imagine if you had to get back in line and start a new order for each item you wanted to buy at a coffee shop? This is where a has_many through relationship came in.

has_many through

I knew that order.menu_items needed to be an array. To solve for this, I needed a fourth model, OrderItem.

OrderItem would be a join table, with foreign keys to the Order and MenuItems models. I thought of each OrderItem record has a transaction instance, representing one Order and one MenuItem at a time. An Order would essentially be a collection of all OrderItem records with the same :order_id. I was a step closer to figuring out what I needed.


At first, an OrderItem model made sense. Until, it didn’t.

Would I need to call order.order_items.menu_items to see all the products in that order? My app had a User model too. How do you build a has_many through a relationship when there are more than three models?

In reality, has_many through only works with three models. But, through other associations, it extends the functionality of those models. If I wanted to know how many MenuItems were in the first order, created by a specific user I could call something like this: user.orders.first.menu_items.count.

Visually, I thought of the relationships between the four models as looking like this:

Visualization of the has_many through relationship of User, Order (which containers OrderItems) and Menu Items.

This was making sense! I would not need to reference OrderItems directly. Active Record does that work for me. Since an Order has many OrderItems, referencing just the Order would give me access to MenuItems. My updated models now looked like this:


With the associations complete, I needed a form to create the Order object. At first, everything seemed to be working. But after looking closer at the console, I realized the transaction was getting rolled back and Order was not saving to the database.

I noticed the :menu_items_id key was listed in my strong params, but I was getting a :menu_items_ids is not permitted error.

To try and resolve this, I worked in the console, testing things out, bit by bit until I could pinpoint where I was getting stuck. In the console, I could successfully do the following.

  • Create an order. order = Order.create(user_id: 1, name_for_pickup: "Rachel", menu_item_ids: [1,2,3])
  • View the value of menu_items. order.menu_items # [1,2,3]
  • Add an item to an order. order.menu_items << item
  • Save the order.

Then it hit me.

Ruby was right in not permitting the menu_item_ids param. I thought I just needed to create an order. Instead, I needed to create an order, find the menu items by id (menu_items_id, which was the unpermitted params) and shovel them into the array. I updated my create order method.

And it worked!

In summary, if you are running into issues with objects relationships, try the following:

  • Verify that the params are correct. Typos can instantly cause object creation to fail. Pluralization like menu_item_id vs menu_item_ids are also something to look out for. All params are strings, which may cause downstream effects if you are expecting an integer or boolean.
  • All model attributes are listed in strong params. Strong params help to prevent users from injecting harmful data into your database via the form. If strong params lists only :name, :email and :password can be submitted in a :user hash, the transaction will fail (and not write to your database, yay!) if an attribute of :not_a_hacker was within your params.
  • Use .create! instead of .create when testing. create! will give more information into what validations may be causing errors. For example, in my app, an Order must have as User (barista) id associated with it. Running Order.create() in the console would not tell me much, but running Order.create!() would print out an error like A User must exist.
  • Append .valid? to objects. A object may be updating. But, is it saving properly to the database? For example, if order referenced Order.create() (an empty object, which will not validate because there is no :user_id), adding .valid? will return false.

All in all, building Central Perk was the most difficult and frustrating project to date. However, I learned a lot about associations, forms, params and creating and overall DRY application. I am more confident in my debugging skills and look forward to improving what I have built so far.

Building a Wine Journal Application with Sinatra

I feel good going into project mode for the Sinatra application.

With my Burger Finder app under my belt, I know what worked, what to expect and what did not work for me last time. I wanted to approach this project with a plan so that I could work efficiently.

I keep a running list of ideas. One that I had been wanting to build for years was a digital wine journal. I have a bad habit of not writing down or taking pictures of wines that I tried and liked. The Sinatra app requires a MVC model, with CRUD commands, so it sounded like a good fit.


I went into detail on planning with my CLI application and followed the same principals in building Wine Journal. Project week was actually two weeks, so I took the first to plan and the second to code. During the first week, I finished any existing labs and revisited new concepts until I was comfortable with them.

I wrote user stories to help me think about the user and how I wanted them to navigate the app. These two were the most important to me:

As a user, I want to see a list of wine bottles that I have tried and added to my collection

As a project maintainer, I want user information to be secure

Writing user stories helped me to think about which RESTful routes I would need, how to structure the /views folder and what methods I would need to achieve what I envisioned for the app.

Sketch of the proposed flow, view and routes for a logged it or logged out user
Sketch of the proposed flow, view and routes for a user.

For Wine Journal, I wrote out the bulk of my application in pseudocode. Pseudocode for Pros explains that by putting time upfront to pseudocode, it saves time later when it comes to writing the code.

# Pseudocode for creating a new bottle object

  • if not logged in
    • redirect to /index
  • else (if they are logged in)
    • require name only
    • check for blank fields
    • create new wine bottle object
    • save to the database
    • associate user with the wine bottle they created
    • wine bottle shows in their collection
    • redirect to /bottles/id
  • end

Looking back, although my pseudocode did not account for everything, it covered at least 80% of what I needed to build.

Building the MVP

The main goals of the Wine Journal were the following:

  1. Have at least 2 models, 1 has_many and 1 belongs_to relationship
  2. Have user accounts where a user can perform CRUD operations only on objects that belongs_to them
  3. Use RESTful routing
  4. Enable user sessions

I met the first requirement by having a User and a Bottle model. A User could have many (wine) bottles in their collection. And a Bottle, a specific entry of a wine bottle, belongs to a User.

For the second requirement, I set up a /signup route. The view included a form with inputs for a name, email address and password. On submission, if none of the inputs are blank, a new User is created, they are logged in and directed to the welcome page.

Wine Journal Signup Form
Signup form for the wine journal app

Signup method checks for duplication accounts and empty input fields

Once logged in, a user would only be able to view, edit or delete bottles in their collection. I handled this in two ways. First, when navigating, a method would check to see if someone was logged in. If they were, then it would check to see if they had permission to view the page.

Get /bottles route checked to see if there is a logged in user. If they are logged in, bottles from their collection are show in the erb view.

Second, as a fail-safe, when a bottle was being edited or deleted, the method would double check that the id of the current user matched the foreign key (user_id column) of the bottle. If everything was truthy, the patch or delete request would go through. If there was a failure, they are redirected to the /login page.

Patch method checked that the current user has permission to edit the current bottle

Enabling sessions allowed me to check if a user was logged in by assigning their user id to session[:user_id]. When navigating to the /logout route, the session has is cleared and the user is directed to the / route.

Using RESTful routes, get  post requests and forms was difficult. I kept getting the routes wrong—did I need patch or post if I was using form inputs to create an object. But, I took it slow and got comfortable with the concepts. I started with basic routes, get routes like  /signup and /bottles before creating the patch and delete routes. I almost forgot to include use Rack::MethodOverride in which allows the Sinatra Middleware to send patch request. Oddly, post was working in place of patch but there may have been long-term effects.

I avoided working on sessions. Even though this app did not have real user data or API keys, I wanted to keep it as secure as possible. I had the idea to use environmental variables to reference the session secret word, but did not know how to do it. I saw some references to hiding API keys with Javascript or Rails, but not within the context of my Sinatra app.

I learned about the dotenv gem, worked without Rails and seemed to be the solution I was looking for. After installing the gem, creating a .env file and adding it to a .gitignore secret keys could be added to .env and referenced in the application.

For example, instead of set :session_secret, "secret" in the application_controller, it could be set :session_secret, ENV["SESSION_SECRET"] which references the SESSION_SECRET> within the .env file, which contains like this SESSION_SECRET="secret".

Plans for the future

I feel like this project went really well. I gave myself the time and resources I needed to succeed. However, there are improvements I would like to make. For a future update, I want to refine this app so that I can deploy it to a service like Heroku or Netlify so that I can access it on the web. Learning to hide sensitive information was a step in the right direction, but there may be additional layers of security to implement. I will have to think about storage, deploying changes, testing and monitoring the app to ensure any vulnerabilities are taken care of.

Keeping Wine Journal DRY was a large part of the project requirements. Overall, my application was DRY, but I know there is room for improvement. I like to take some time away from a project (and after it has been reviewed) before I refactor it. That way, there is less risk of breaking it ahead of it being reviewed.

I would like to refactor common or similar patterns into new helper methods. At several points in my application_controller I confirm if the current user has permission to modify an object. This can be refactored into a has_permissions? method and referenced within other methods.

The routes and redirects I set up keep the user from getting stuck at a page with no direction. However, error messages to explain why they have been redirected is something that I want to incorporate. The Sinatra Flash gem is one I am looking into.

The scope of this project did not include accessibility, load times or progressive web applications (PWAs), but I would like to incorporate those concepts. I learned about PWAs last year during the Udacity, Mobile Web Specialist Nanodegree and would love to do more! It would be really cool to be able to access the app offline, store any changes locally then push them to a server when the connection is available again. I’ll be able to add wine notes anywhere!

Overall, I am happy with this project and look forward to being able to add to it.

The code for Wine Journal is available for use on Github.

Screeshot of Wine Journal homepage
Screenshot of Wine Journal homepage

Wine bottle icon provided by Font Awesome. No changes were made.

Hiding Sensitive Information with Environmental Variables in Ruby

It’s project week!

This means I have been spending my available time working on my Sinatra application. User sessions are one of the requirements. It involves enabling sessions and assigning a secret key or word to that session.

Which had me thinking, what is the purpose of a secret word if it can be seen in a public Github repository?


I heard of environmental variables and wanted to see if that would work here. I found several references to hiding sensitive information or API keys but none that fit in the context of my project. With trial, error, and help from the Flatiron community, I figured out a way to hide sensitive information using environmental variables and the dotenv Ruby gem.

This post outlines how to set up environmental variables and some common gotchas that you may run into.

I have written these directions in the context of the Sinatra project that is part of the Flatiron School Software Engineering course. The principles can work for other setups but may require revisions. If you are a Flatiron student working on this project, I highly recommend using the Corneal framework.


  1. In your project repo’s, Gemfile add gem 'dotenv'.
  2. In environment.rb ( this is located within the /config directory if you are using Corneal) add the following:

    require 'dotenv'

    I added mine after ActiveRecord::Base.establish_connection although you may be able to place it elsewhere within the file.

  3. Run bundle install.
  4. In the root directory of your project, if you do not already have them, create a .gitignore and .env file.

    Within the console, a new file can be created by entering touch followed by the name of the file.

  5. Within .gitignore add .env.Any files or directories listed within .gitignore are now not being tracked by Git. Changes to the .gitignore should be tracked, committed and pushed to your remote repo. Your .env should not be tracked, committed or pushed to a remote repo.

You can now use the .env file to keep API keys, session secrets and more. To do that, assign a key and it’s value using this syntax:

NAME_OF_KEY="This is the value of NAME_OF_KEY"

In your project files, reference that value by using ENV["NAME_OF_KEY"]. Since .env is not tracked or pushed to your remote repo, your code will only contain the reference to the value instead of the value it’s self.


I ran into several issues with my app not loading after starting the server. Installing the dotenv with gem install dotenv did not seem to work, but manually adding it to the Gemfile did.

If bundle install has been run and there are still unexpected results, double-check value names and where they are being called. For example, ENV["NAME_OF_KEY"] may need to be escaped if it is part of a string or within a .erb file.

Is anything safe?

Not really.

If you have previously committed or pushed sensitive information to a repo, consider it stolen. Update any passwords or generate new API keys as soon as possible. Sensitive information can be removed from Github, and previous commits can be reverted but that information may exist in a forked repo on someone else’s computer. Even if a repo is private, that information still exists on a server somewhere. If someone gained access to that server who shouldn’t (hello data breaches), they will have access to that information.

I am not trying to scare you. Just to think about what information you are posting on the web.


Photo by Michael Dziedzic on Unsplash

CLI Have No Idea What I’m Doing: Planning (and Building) My First CLI Application

60 days into my Flatiron bootcamp and the first project—a CLI application—is due in a few hours.

Looking back over everything I learned, all the parts needed to build a CLI app were covered, but the idea of building something from scratch was still intimidating.

Yes, we had built CLI apps as part of the course material, but this was different. The safety net of a test suite or being able to hit the ask a question button was missing, this time.

That, in addition to the unknown of how much time it would take to build had me feeling anxious.

if anxiety == unknown
     puts "screams into the void"

Luckily, anxiety caused by the unknown can be resolved by planning and presenting yourself with facts instead of “what ifs”. So, planning felt like a logical first step to tackling this project. This post will cover the planning steps I took to get started, related resources and thoughts on what I would like to implement in the future.


I was very tempted to jump right in. To get ahead of the clock. But just like grocery shopping without a list leads to disastrous results, making a list of what skills, tech and methods I need would help me to stay focused and avoid being surprised.

In my case, there were specific project requirements so I started there. Reading over the requirements, making notes and asking a question if needed was the first step. I did this before writing any code.

Even if you do not have project requirements, think about what you want your CLI app to do. Here are some questions that came to mind for me:

  • What is the purpose of the program? What will it do?
  • What outside resources or data will it need?
  • How will the user interact with the CLI?
  • Will it take any inputs from the user?
  • What outputs should it have?

For my application, I wanted to display data showing burger restaurants (or restaurants that sold burgers) nearby.

Programmatically, this is what I want to happen.

  1. Get all local burger restaurants
  2. Display name, rating, and location
  3. Prompt user to input a restaurant
  4. Display more information

It doesn’t have to be perfect, just enough to the core concepts across. This also helped me to avoid scope creep with my own project.

Relating to technology, I knew I needed a website to scrape data from (as part of the project requirements) and settled The 15 Best Places for Burgers in Baltimore on Foursquare. I choose this page because the source code had well-named CSS classes that would make it easy to target and scrape the sections I needed.

I wanted to use Bundler to set up the project and Nokogiri to do the actual scraping, so took the time to read through their documentation. For me, reading documentation (and project requirements) in detail helped to ease my anxiety, feel prepared and maximize my time.

At this point, I was ready to start coding.

Building the CLI

Getting the skeleton of my project was the very first step. At first, I wasn’t sure which files or folders were best practices. Then, the Bundler documentation made it very easy to get started.

In the terminal, all you have to do is the following:

bundler gem name_of_your_project

For my project, it looked like this:

bundler gem burger_finder

Small note that I learned the hard way. Ruby uses snake case as a naming convention. While bundler gem burger-finder isn’t wrong…it does make for weird folder formatting, so it’s best to stick with snake case.

At this point, I will admit, I felt stuck. While I knew how to build the methods I would need to create the parts of my CLI, I did not know how to get the CLI its self to work. Or, what all these mystery files that Bundler created are for. So, as opposed to muddling my way through it, I read Dissecting my Ruby Project Skeleton which I found helpful in understanding the parts I was working with.

Once I could get my program running via ruby bin/start in the command line, I was good to start building my methods and chaining them together as needed.

For the most part, building the pieces went smoothly. However, getting the pieces to work together while returning the correct data did take some work. Setting up a console so that I can peak into the code (like with binding.pry) instead of running the whole program was helpful too.

My biggest blocker was getting 403 errors when scraping my webpage. Understandably, I had been flagged for hitting the site too often in a short amount of time.

As a workaround, I created a static version of the main page for the initial scrape (since I would be hitting that one the most) but will go out to the venue’ specific page for the details. A quick search showed the following as a fix that so far, as kept a 403 error from happening when scraping the detail pages.

Nokogiri::HTML(open(url, 'User-Agent' => 'ruby'))

The Future

Earlier, I mentioned scope creep as something I wanted to avoid. I find it easy to want to do all-of-the-things when its best to focus on the basic requirements first, then refactor and add features afterward.

That said, I here as some of what I would like to add to this project in the future:

  • Implementing an API: It turns out Foursquare’s Places API is perfect for this! Getting set up was easy and free but I did not have enough time to implement it before my project due date. Understanding the API and how to manipulate and display the data is on my to-do list.
  • Location by input: I’d also like to get location data from the user via input so that I can display more relevant restaurant information. Again, the Places API would be perfect for this, but there may have been a way to append a zip code to a URL which would be used to scrape data. For example, would display burger joints in Beverly Hills.
  • Edge cases. Right now, my application assumes the user will only enter correct inputs. In a real-world application, this is not realistic. I’d like to include messaging that responds to an input that is outside of the available range. For example, if the user wants to know about the 20th restaurant object when there are only 15.
  • Error Handling. Custom error messaging was covered briefly in our course material, but I would like to explore it more. If something was broken how can I communicate that with a user? Error handling ties into the edge cases I mentioned above.


Overall, I am happy with how my burger_finder project came out. It’s not perfect, true, but I implemented a lot of what I learned in the past two months. It’s weird to think that earlier this year, I had never written a line of Ruby.

Now, I’m not far off from being able to create a program from scratch and publish it as a gem. I’ve gotten better at troubleshooting errors, debugging and making progress even when it feels like I am stuck or out of time.

Now that my project has been submitted, it’s time to sit back, reflect and prepare for the project review.

Maybe I’ll grab a burger for dinner. Is there an app for that?