Creating a Rails App: What I Learned
For my first Rails app, I created Menu Info: A platform where anyone can create menus and menu items, and add tags to help sort those items by various attributes.
I started my project off by using Rails’ incredibly useful resource generator ($ rails g resource <ResourceName>
) to create all of the resources I needed: Users, Restaurants, Menus, MenuItems, and Tags. While Rails has a bunch of similar commands, the resource generator was the best for what I needed because it does the perfect amount of work for you. It’s a great middle-ground between the scaffold generator, which creates too much junk, and the model/controller/migration generators, which are very specific in what they create. It’s very much comparable to the middle-sized bear in the Goldilocks and the Three Bears tale.
The first real issue that I ran into was when I was creating a model for my join table. I wanted to create a join table for my ‘menu_items’ and ‘tags’ tables, so I created the join table ‘menu_items_tags’. However, when I went to create a model for the newly-created join table and used the same name, I started to run into issues. Turns out that while join tables use the ‘plural_plural’ naming convention, join models use the ‘plural_singular’ naming convention. This threw me off because I assumed that both would share the same naming convention. However, in hindsight, I realized that it makes total sense because models/class names are always singular, and tables are always plural.
One thing that I had to keep in mind was that I had to maintain referential integrity. This is super important because having orphaned records in your database is sloppy and could cause a ton of issues down the line. In my app, I used dependent: :destroy
with my models’ ‘has_many’ associations, which means that whenever the parent record is destroyed, all of the associated child records are automatically destroyed as well. One example of this was with my User and Restaurant models.
class User < ApplicationRecord
has_many restaurants, dependent: :destroy
end
Destroying the user record also destroys the records of all of the restaurants associated with that user. I also used this to chain together multiple models, meaning that destroying a user would destroy that user’s restaurants, which would destroy that restaurant’s menus, so on and so forth.
Another issue that I ran into was when I wanted to permit an array through strong params. For my MenuItems model, I wanted the user to be able to add pre-made tags to classify what kind of dish they are posting. I made a join table for this and added a collection checkbox to the form. The issue arose in my edit and new actions where I couldn’t seem to find out how to permit the array of tags properly. After several minutes of Googling and reading through Stack Overflow questions and answers, I found out that instead of permitting the ‘tag_ids’ symbol, I should permit the hash ‘tag_ids: []’. This is because, without the empty array, Rails wouldn’t know that the parameter is an array.
For my restaurant view, I wanted to embed Google Maps to show the location of the restaurant based on the address. For this, I needed a way for the embedded URL to include a query string. At first, I used string interpolation. This would’ve worked, but the string wasn’t URL encoded and was causing issues. After some research, I found that you can use the URL encode helper ‘u’ to encode a string.
address = "82 Smith St, Providence, RI 02903"
u address #=> "82%20Smith%20St%2C%20Providence%2C%20RI%2002903"
The last major issue that I ran into was when I was implementing custom routes. I wanted my custom get route ‘/menu_items/dollar_menu’ to have it’s own view and action, but whenever I navigated to that URL I would get an error telling me that it couldn’t find a menu_item record with the id of ‘dollar_menu’. I quickly realized that this is because there was already a get route named ‘/menu_items/:id’ which was my menu_items show route. To remedy this, all I did was move the custom route above the menu_items resources line. Doing this made sure that Rails processed the custom route before the resource routes and didn’t get confused by trying to process the wrong route.
Overall, while I am still very much a beginner, I feel like I have a much better understanding of Rails after completing this project. While completing lessons and labs is great, the best way I learn is by putting the knowledge that I learned to the test through trial and error. There’s definitely a lot of magic that I don’t yet fully understand, but I look forward to my journey of diving further into Rails.