After having added the “custom list” functionality in the last post as a backup for a failed url parse, it was time to add it as an actual feature that the user can access. After all, what if you wanted to use a recipe that wasn’t online, or was in a format that couldn’t be automatically parsed?
A Spot of Refactoring
First, this required a bit of refactoring. I touched on this a few posts ago, but the code that was involved in the creation of a new list and recipe was not packaged in a way that could be easily reused. This wasn’t a problem when there was only one way to create a recipe and a list, but now that I’m adding more than one way, we need to generalize this code.
I did so by first splitting the code that creates a recipe and a list, and transferring that code to my utils.py
file:
Note that my current database model requires a recipe_url
, and I plan on changing that, but I didn’t want to fall down the rabbit hole of database changing just yet.
Then, I split off the code that parsed the recipe from a url into its own function:
By splitting the create_recipe()
function and then calling it here, I could then create a second function to create a recipe from provided text:
Once this was all finished, the actual code in my routes.py
to create recipes was drastically simplified. Here’s the new backup form:
With this out of the way, it was time to add the new functionality to the app.
Adding the Custom Recipe Option
The first place I wanted to add the feature was in my home
route. I conceived of this as a second option to start a new list: you could enter in the url, or you could type/paste a list of ingredients. First, I added the CustomRecipeForm
to the main.home
route, and wrote the logic for what to do when it was validated. Thanks to the refactoring I did above, this was quite easy:
Behold, the power of refactoring. With just a few lines of code I was able to create a completely new way to initialize a list. All that I needed to do was add the actual form to the template. I put it in the <jumbotron>
object, below the url form I’d been using thus far:
This created a nice, simple new piece of the UI:
Clicking the “Find Ingredients” button would then redirect the user to the “clean list” page, where the rest of my code would take over.
For my next piece, I wanted to also add the option to paste recipe lines on the actual list page. I again added the form to my main.compiled_list
route, and thanks to my earlier refactoring, the code was again simple to implement:
I have to be totally honest here: I’m pretty proud of how easy it was to implement these features. It shows that I’ve structured my code well and that the refactoring was a positive use of my time. I don’t want to pat myself on the back too much (who the hell knows if this is even that impressive, tbh), but dammit I’m proud.
Anyway, horn-tooting aside, I still needed to add these features to the list_page.html
template. Following my lead from the homepage, I added it to the already existing modal that was being used to paste a new url:
Checked the modal and it all works:
I pasted in a few recipes, just to make sure everything was working, and so far so good.
Next steps:
- ability to export the list to print/email
- increased list functionality (delete lines, temporarily cancel them out)
- move lines around?
… and plenty more. At this point I’m beginning to realize that I need a roadmap to figure out when I can call this thing “feature complete.” I have a ton of ideas, but I want to have a “v1.0” out first, with a certain bare minimum functionality, before I chase after some more of my more involved ideas. So expect a roadmap post coming in the near future.