Selecting a topic
I find that selecting a topic is one of the hardest parts of a project for me. I worry preemptively that I’ll never be able to come up with a good idea, that I need other people to think through ideas with, that my ideas are all lame 😒 This time though, I brainstormed a list of ideas 💡 and found one that really struck home.
Picture this: you are feeling ambitious and have decided to cook dinner instead of ordering takeout for the fifth night in a row. Somehow, you see some produce in your fridge that hasn’t gone bad, AND you know you’ve got some staples in your pantry. Sweet. So you go searching for a recipe, find one that looks good, open it up and then… you see the ingredients list. Tapioca flour? Coconut oil? Matcha? Hemp seeds? Almond milk? 🤯 And just like that, you feel your motivation and ambitions drain away and you’re left picking up your phone and opening DoorDash for the sixth time this week. If only you’d been easily able to find a recipe that was made up of ingredients that you already had.
So here’s the thing — I know there are apps that do something similar, but I’ve never had great luck with them. You can enter ingredients that you have, pull up some recipes, but I always found that if I was lucky, those recipes would have three ingredients that were already in my pantry. On top of that, they would always propose recipes that didn’t fit my diet (aka, I’m vegan and the recipes suggested were not 😩). The idea I’m proposing allows you to access a list of recipes based solely on what you have in your pantry/fridge. You would create a “pantry” and enter the foods you already have, then go searching for the perfect meal 🥘 Easy! (The dietary restrictions aspect is still under construction as of now)
Obstacles in building
Okay, not all of it was easy exactly. In my bootcamp, we’re learning Ruby on Rails (which is awesome), and using that with ActiveRecord to build our apps. There are several aspects that I found particularly difficult, which I’ll review here.
Gah maybe the literal bane of my existence, forms are such a basic building block but for whatever reason I struggle to get the syntax to stick in my mind. There are a couple of options for forms: form_for, form_tag, and form_with. All of the forms have a default method of post, but you can change that — just something to be aware of.
Best when used with a specific instance variable that represents a model in your schema. You might choose this to add a new instance, or edit an existing instance of a model object. Here is an example of the syntax:
After the form_for keyword you write the instance variable representing the model object that the form is… for. Heh. The ‘f’ is part of a Form Builder that is associated to the model object. You add labels and fields (they can also be password_fields, number_fields, etc.) and then at the end “f.submit” creates a button to submit the form. It will automatically create a label on the button, so if you want a different label, add in quotes after submit ‘button label’ (i.e. <%= f.submit ‘button label’ %>). Don’t forget to end the form! And everything should be in the “ice cream cone” with equals sign tags (<%= %>) except the “end” (just “ice cream cone” <% %>).
The collection_select helper is one of my favorites, though one I found complicated. It allows you to create a dropdown if the model has an attribute with multiple options. The syntax looks like this:
The first field, :food_id, represents the attribute of the model within the form (in this case, @ingredient has an attribute of ‘food_id’). The next field, @foods, represents the collection for the dropdown, from which the user can select. The third field, :id, is the data that the form will send (so the id of the food that the user selects). The fourth field (and this is part of the collection_select magic) is what the user sees 👀 so instead of having to select from a list of meaningless numbers, the user gets to choose from a list of food names (and Ruby still understands and passes around the id for the corresponding food object).
I personally didn’t use these in my project, as I prefer form_for and form_with and this is an older form helper (as is form_for apparently). This form helper is best used for more static needs such as logging in or search, that are not tied to an instance or model. Syntax:
As you can see, form_tag includes the route for the form (in this case, “/search”) as well as the http method specification. The “do” keyword is still included, but there is not a Form Builder (“f” in the form_for example). Therefore, all of the tag names are followed by the word “tag” — “label_tag”, “text_field_tag”, etc.
The great part about form_with is that it combines the ability to send a form to a specific url like form_tag, with the ability to use a form directly with a model, like form_for. I used it as follows:
You still get the Form Builder but you also are able to input a url instead of being tied to a model. As I mentioned earlier, form_for and form_tag are being deprecated “softly”. The good news is form_with contains the best of both worlds, and there are many ways to use it.
It has been promised to me that once we learn React and some other tools in a later module, this will be much easier, but adding the CSS and HTML has been a struggle for me. The key that I’ve found so far is when you have two elements that you want to work with as a single unit, wrap both of them in a div (or span or nav, depending on what elements they are). A div is a more all-encompassing tag while a span tag is for accessing certain elements within the page (a portion of the page or text). The nav tag is used to encompass a set of links or navigation elements (think moving around the app). Finally, in order to add CSS to certain tags, giving them classes is super helpful so they are easily accessible in the CSS and you can quickly tell which element you are using.
The header class contains the elements that I always want at the top of the app and then the nav class has some links to either signup/login or logout if the user has already logged in.
Here you can see how I access the class (“.classname”) and used the nav tag to access a specific element (the one with the “right” class name, “nav.classname”) within that nav tag. I’m sure there are other ways to do this as well, this is just how I resolved some of my issues. I also know that bootstrap is a popular gem for styling in Ruby so that might be worth checking out.
Why it is hard
For me, I just struggled a lot with figuring out how to access the current user (i.e. user of the app) and where to store the data about that user. Does it go in the UserController? In the ApplicationController? What even goes in the ApplicationController?? So many questions 🤔
How it works
Then, I learned that you can just… build a SessionsController. And that’s where you update and store data about the current session, i.e. who is currently logged in/using the app. In order to access the current user, you need to check the session for a user (remember, you set the session to have a user in the SesssionsController, most likely when the user logged in). Since you will probably do that in many places in many controllers, it makes sense to put that into the ApplicationController, as all the other controllers inherit from that, and therefore will have access to that method.
The create function is where the sessions data is set to later be used for finding the current user. We are assuming here that the user has already signed up and thus is in the users table.
The current_user method will be used in other controllers when the user is needed (say, to display all the foods that the user has in their pantry).
While I don’t have it in these examples, you can also add authentication and authorization to your app using the session. You can prevent a user from viewing certain pages if they are not logged in (i.e. session[:user_id] is empty), and instead redirect them to the login page. You could also limit certain pages or actions to only be viewed or done by certain users (say you only want the user to be able to edit recipes that they created themselves).
Overall, I have been very excited to work on this project. Not only is it close to my heart (could you tell that my example at the beginning was referring to me?), but it has a lot of potential (in my eyes). I would love to be able to expand the app to include dietary restrictions and to generate shopping lists for users, among other features. On top of all this, it has been a huge learning opportunity. I’ve gained a new appreciation for creating websites — there is so much that goes into them! Hopefully I’ve been able to show you some useful concepts, and encouraged you to keep an eye out for my app — What’s in your pantry, coming soon!