The Initial Idea:
I wanted to create an app where a user could select an ingredient that they had in their home and be given a random recipe to make. I am an indecisive person, so I thought it would be nice to have an app that made the decision for me.
This app uses a Rails API back-end with PostgreSQL for the database and asynchronous Javascript for the front-end. It is a single-page web app, with all requests to the API being made with asynchronous fetch requests.
The Back-End:
The back-end of the app was pretty straightforward. I used the 'rails new' command with the --api flag to get the basic files going. I added the 'fast_jsonapi' gem to make serializing my data easier, as well as the 'rack-cors' gem to allow cross-origin resource sharing.
This was my first time using PostgreSQL, so I had a few issues setting it up. I realized that I needed to run the database server on PostgreSQL in order to create and migrate my database, something I hadn't needed to do with SQL previously.
I decided to have three models / tables for my backend:
- Recipe - This model has a title, recipe link, and image link.
- Ingredient - The only attribute is an ingredient name.
- IngredientsRecipe - This is join table between recipe and ingredient, since it is a many-to-many relationship.
For my API, I knew I would be getting most of the data for my front-end from the recipe index page, so I created the controller action and serializer for that first. In the serializer class, I included ingredients as an additional attribute so that the recipe index page would include the ingredient names for a specific recipe. I also ended up creating a recipe show action to get a random recipe by ingredient name (more on this later), as well as an ingredient index page so that I could use that data to populate my ingredient drop-down menu.
The Front-End:
I started building out my front-end by adding an index.html page, an index.js page, and a styles folder with a CSS file. I initially wrote all of my Javascript in the one file and re-organized it into a Recipe class and Ingredient class, however I wasn't very happy with this level of organization. Even though the recipe class had methods that somewhat had to do with recipes, some methods made calls to the API, while others rendered content to the page. I eventually decided to re-organize my code into more classes and files and ended up with the following:
App class - This class gets instantiated from the index.js file and creates a new instance of the Recipes class
Recipes class - This class handles most of the functionality of the app such as rendering data / HTML to the page, binding event listeners, and getting information from the RecipesAdapter and Recipe classes.
Recipe class - The main function of this class is to create recipe objects from the API data, and use that data to create HTML cards to render.
RecipesAdapter - The adapter makes get and post fetch requests to the API and parses it to JSON for the other classes to use.
Ingredients class - I created this class to populate a drop-down menu with all the ingredients from my API.
IngredientsAdapter - Like the RecipesAdapter, this class makes a get request using fetch to the ingredients index action of my API and parses that data for my Ingredients class to utilize.
Styling:
This was the first project I have worked on where I completely styled it myself using CSS. In the past I have used templates or bootstrap for styling, but I wanted to improve my CSS skills while making this project.
One noteworthy thing I learned about is flexbox. I used this to display my cards evenly and wrap them in a row. Although my use of it was pretty simple- making evenly sized cards, I can see how useful it would be for other types of layouts.
Main Challenges:
I debated over the best way of getting a random recipe from my recipe show action by ingredient name. I ended up passing the ingredient name as a parameter in my route, however I'm not entirely sure how RESTful this is. I could have created JS ingredient objects with name and id properties and passed the id as a parameter to a join table show action. However, I would have to nest the recipe data in that end-point to get what I needed, or make another get request once I had a random recipe id. Another option would have been to make a get request to an ingredient show action. However, since I was fetching mainly recipe data, I decided to fetch from the recipes show route.
Organizing my Javascript code was more difficult than I anticipated. The more abstracted the code was, the harder it was to understand bugs and how the overall app was functioning. For my next Javascript project, I would like to plan out my organizational structure beforehand instead of writing it all in one file and then changing it later.
Final Thoughts
This was a really fun project to work on. I got a better sense of Javascript's prototypal OOP style and also brushed up on my CSS skills along the way.
As a note for the future, I would like to potentially add a couple of features to this app:
The ability for a user to delete a recipe from the API
A CSS animation to increase my skills further
Figure out a way to get more recipe data for the app
If you have any feedback or questions about Mindless Meals, don't hesitate to let me know!
Top comments (10)
Hey!
I stumbled upon your article and since I'm mostly working on JavaScript at the moment, I thought it'd be nice to work with Ruby and Rails to keep my skills updated and fresh :)
Plus, I wanted to work on todo/habits management!
I started contributing to your project. Let's discuss things further if you're willing too.
That sounds like a great idea! When I get a moment I will look at your contributions.
Thank you for checking out my projects!
Hi Rachel. Fellow Rails developer here. Nice to know that people are still learning Rails. I recently created a Rails App for "Jain Food". I had to collect recipes from multiple receipe apis to get a decent number of recipes in my database. Nice post and all the best for your job search.
Hi Vikram, thank you for reading my blog! I definitely could use some more recipe data for my app. Thank you for the advice!
Really well described, well done!
Is there anything stopping you from putting this live using Heroku/Digital Ocean and having it form part of your portfolio?
Thank you so much!
I will probably deploy it on Heroku once I am done with my final project. I don't have experience with that yet, so it may take me some time. If you have any good resources let me know!
Great post describing your project! I especially like how you added what aspects challenged you the most!
Also, awesome project idea!
Thank you Victoria! I've found it helps me to write down my challenges, so I know what skills I can improve in the future.
Thank you for checking out my project!
Neat work
You could choose to implement a simple search function to avoid the restful dillema while keeping Id based fetch for only recipe name and id
Great idea! Thank you for the suggestion Rupertt!