MyFamilyRecipe React/Redux app using Rails API
Tags: react, redux, rails
Published: 2020-07-13 05:28:02

I can't believe it's finally here. I was reflecting today that this time last year, I had started learning to code a little bit of JavaScript on Grasshopper App and today I am submitting my final project at Flatiron School. Let's jump in.

I came about this idea when talking with my husband. He tells me that I need to get his grandmother's recipe for one particular chicken dish that he likes from his mom. I had said that I'll just copy it from her notebook the next time I see her. I was hesitant about asking my mother-in-law for recipes through a text message because she would send me pictures of these recipes that were very hard to read. I would rather just copy it down myself. It dawned me that I could make an application that keeps track of family recipes and the idea grew from there.

It started out as a simple application where a user can submit recipes. My potential for this will be to create a social media type platform where users can share family recipes and users can scroll through a list of recipes and comment on them. I didn't quite get around to implementing commenting on recipes for this project but I would like to add this feature in the future. I ran into a few roadblocks so I'd like to highlight three of them. The three roadblocks I want to highlight are the following: 

1. Rendering the correct links in my navigation bar when a user is logged in.
2. Understanding Redux store and implementing asynchronous fetch using Redux Thunk.
3. Managing changes in a nested form.

The last roadblock was a particularly tough one and it made me feel really accomplished when I found the solution. I will touch on these roadblocks and elaborate on what I did to achieve the solution.

#### Roadblock #1: NavBar
I wanted to build a navigation bar so I built it using [react-bootstrap](https://react-bootstrap.github.io/getting-started/introduction/). I also wanted it to be dynamic where it would render different links when a user signed in. I used a conditional to render different results and stored it inside an arrow function called `renderNavbar`.

*NavBar.jsx*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3rtu57p5ju1jq1jhoo8k.png)

I then pass in the state of current user from my Redux store on line 60 and set it to a boolean value using `!!`. When a user is logged in, they should be able to view the recipes they've added, add a new recipe, and edit their own recipes. It also shows a logout link when a user is logged in and when they log out, it will show a sign up and log in link. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/n3y1mba7l34h8ltot08c.gif)

#### Roadblock #2: Understanding Redux and Thunk
In order to fix the first roadblock, I had to understand the second roadblock first. The example I will use for this will be the `currentUser` reducer. The `currentUser` is a reducer in the Redux store. I utilized `Redux Thunk` to make fetch requests to my Rails API to get the current user stored there. First, I have a file called `store.jsx` that stores of my reducers and combine them together with `combineReducer` like so...

*store.jsx*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xqra6cu9bims9robac3d.png)

I made an asynchronous action creator inside my middleware folder called `actions` and make a fetch request to a custom action inside my `SessionsController` in my Rails API.

*actions/currentUser.jsx*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wlg5kfo8j5boq35q1mj6.png)

Custom route in *routes.rb*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/k1sd24qiiskerb8amqfi.png)

Custom action in *sessions_controller.rb*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ikzzfo1xx4ltr2kao1m9.png)

`logged_in?` on line 16 is defined in `application_controller`

*application_controller.rb*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jhoul4pvbvbom4dstakd.png)

In addition to using `currentUser` state from Redux store in `NavBar.jsx`, I also used it in my `RecipeCard` component to render a link to edit a recipe only if a `userId` is equal to currentUserId`. This authorizes a user to edit only a recipe that belongs to them. 

*RecipeCard.jsx*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dw9lerryt5u8v0bf7mgv.png)

#### Roadblock #3: Managing Nested Forms
This application has three forms total: 1) signup form, 2) login form, 3) recipe form. Both signup and login form state are managed by Redux. I originally was going to use Redux to manage recipe form as well. The problem I ran into with recipe form was that it was a nested form. The three main models in the backend have these relationships: 
* User has many recipes
* Recipe has many ingredients and belongs to user
* Ingredient belongs to recipe

I was running into a problem handling changes in the ingredient field form. It wouldn't show the changes in the correct attributes in Redux store. Because a recipe has many ingredients, I also wanted there to be a button that will continually render ingredient fields as I needed to add more ingredients to the recipe. One of the things that fixed it was adding this line of code in `recipe.rb` in API.

*recipe.rb*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bt47vvd2101f738z36or.png)

I had completely forgot about `accepts_nested_attributes_`! I also needed to add this to `strong params` in `RecipeController`.

*recipe_controller.rb*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tttji2q5udu9tjbgh0u4.png)
I added an attribute called `ingredients_attributes` as an array with attributes from ingredients table. By doing this, the `RecipeController` is in charge of creating ingredients in the form. Previously, I had both controller in charge of their own CRUD actions. One of the ways I tried to work around this was creating a separate recipe form component and an ingredient form component and importing ingredient form component into recipe form. Now that recipe is responsible for creating ingredients, there was no need for two separate form components. I made a new recipe form that handled form state locally but still submits form data to Redux store where recipe data is stored. Inside the local state in `RecipeForm`, I assigned ingredients as an array of objects. 

*RecipeForm.jsx*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5h1n89s39hizbdih57fb.png)

By assigning `ingredients` to an array, I was able to map through it and each time the button "add a new ingredient" is clicked, a new ingredient is added to the array. 

*RecipeForm.jsx*
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/os79vihq65p54nkrduv1.png)

The `Add a new ingredient` takes in onClick `addIngredient`. The `addIngredient` handles adding a new ingredient instance to the previous state of ingredients. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5sw5w9png77keaob3xua.png)

The recipe form renders with one ingredient field with a button to allow a user to add as many ingredients as they would like. 

I am glad that I was able to get through these roadblocks. I have so many more plans for this application and I will continue to work on this project. I do plan on deploying this application on Heroku once I have decide how I want the RecipeCard component to look. It has been an insane ten months and I have come a long way. I came into Flatiron School not knowing how to code and now I am able to build a full-scale web application. I am excited to learn more and continue on this journey!

![react-project-demo](https://user-images.githubusercontent.com/52929582/87613777-4e7ad900-c6dc-11ea-8f3e-b97e85a97f69.gif)

[Frontend repo](https://github.com/chayadeaver/recipes-client)
[Backend repo](https://github.com/chayadeaver/recipes-api)