Final Project - User Profile
Tags: rails, react
Published: 2020-04-29 20:05:33

---
title: Final Project - User Profile
published: true
description: The mess, frustration, headaches and final triumph of figuring out how to build this out.
tags: rails, react
series: Mod 5 Final Project
---

# Summary
So, yeah. This took a lot longer than I anticipated it would because I over estimated how much I understood and remembered about basic CRUD functionality in rails and how react ties into it all. I am not going to belabor the point by talking each line of code here but I will post it all, along with the notes I took to keep track of what it was all doing.

# Rails model, controller and route
There are so many ways one can build a user profile. Make it part of the user model, keep it separate (I did the separate model), will the profile have unique information that only associates to a user or will it also contain information from elsewhere in the app/database/3 rd party data pulled in ....? I choose to make it a 1:1 association that does not contain any non user information. Basically I could have put all the same columns into the user model. Keeping them separate but associated made it easier for me (or I thought it was going to) to build the routes and needed CRUD functionality.

The first issue I came across with the profile was that before a user created a profile there was nothing for the profile component to display and that gave me errors. Ultimately it was decided (myself and instructors) that when a new user was registered that the controller would also make an associated profile record with default data ("first name", "last name" that kinda stuff), in order for the profile page to have something to render. While this solved many problems what it caused was a rabbit hole of issues getting an Update route to work in a way that I understood and could replicate for future models/features in the app.

Here is what I finally got to work. For any one reading this more experienced than myself (that would be all of you FYI), please feel free to blast my potential "code smell", and non DRY-ness .... I am a dev noob, here me type way too much ;)

***profiles_controller.rb***
```ruby
class ProfilesController < ApplicationController
  include CurrentUserConcern

  def show
    profile = Profile.find_by(id: params[:id])
    render json: profile
  end

  def update
    # grab current_user id to build a profile onto
    # try is built in
    # {profile: {firstname, lastname, ....}}
    profile = Profile.find_by(id: params[:id])
    profile.update(
      firstname: params["profile"]["firstname"],
      lastname: params["profile"]["lastname"],
      bio: params["profile"]["bio"],
      birthday: params["profile"]["birthday"],
      # user_id: @current_user.id,
    )

    # conditional to render json object of a status notification, a boolean for logged in, and the user model data
    if profile
      session[:user_id] = @current_user.id
      render json: {
        status: :updated,
        logged_in: true,
        user: @current_user,
        profile: @current_profile,
      }
    else
      render json: { status: 401 }
    end
  end
end
```
> not sure if the `show` method needs to be there, but it's staying in because everything in my app to this point is working. I took a lot of similar code from the registrations controller as that controller creates a user, so the I figured they would have similar structure and such.

Next is the routes for the profile.

***routes.rb***
```ruby
Rails.application.routes.draw do
  resources :sessions, only: [:create, :update]
  delete :logout, to: "sessions#logout"
  get :logged_in, to: "sessions#logged_in"
  # update :update, to: "sessions#update"

  resources :registrations, only: [:create]

  resources :profiles, only: [:show, :update]
  # resources :users, only: [:show] do
  # end

  root to: "static#home"
end
```
> I ultimately decided on not nesting the profile update route in the user route because the user routes aren't needed; the user "stuff" is handled in sessions and registrations.

Over in React land, the component I created for updating the profile (UpdateProfile, I know ... surprise naming convention). The part that gave me the most challenge was the part where I had to actually update the backend from the frontend. Here is the function in its working form that patches the profile record correctly.

***UpdateProfile.js***
```js
...
handleSubmit(event) {
    // console.log(e.target.value);
    // const { firstname, lastname, bio, birthday } = this.setState;
    // const uId = this.props.user.id;
    const pId = this.props.profile.id;
    // console.log(this.state);

    axios
      .patch(
        // "http://localhost:3001/profiles",
        `http://localhost:3001/profiles/${pId}`,
        {
          profile: {
            firstname: this.state.firstname,
            lastname: this.state.lastname,
            bio: this.state.bio,
            birthday: this.state.birthday,
            // user_id: this.props.user.id,
          },
        },
        { withCredentials: true }
      )
      .then((resp) => {
        // console.log(this.state);
        if (resp.data.status === "updated") {
          console.log("profile has been updated", resp.data.profile);
          this.props.handleShowUpdateProfile();
          // this.props.handleSuccessfullAuth(resp.data);
        }
      })
      .catch((error) => {
        console.log("update error", error);
        // alert("update error", error);
      });

    // event.preventDefault();
  }
...
```
> Getting the correct match up of data structure between the frontend and the backend was tricky as I seem to mis bad spelling and transposed characters really, really easily. This gets the job done just fine though.

The function `this.props.handleShowUpdateProfile()` is passed down from the parent component that holds both `UpdateProfile` and `Profile` components. I have `UpdateProfile` rendering in a conditional statement based on a boolean state. This ensures that the `UpdateProfile` component - which is just a form - is hidden upon correct saving of data back to the controller - that's the `if (resp.data.status ......)` portion of the promise. I really like how placing a conditional based on a status that is sent from the backend you can kind of force the an order of operation to what is actually async behavior. 

***I take no credit for this, the video series I watched that helped me build the user authentication system used this, so I stole it like a good programmer***

# Note taking and Keeping Track of What the Flip is Going on in my App
To say I got lost in the logic and data flow of my the little app that I have is an understatement. Just the user authentication was a knot I had to untie each time I sat down to work. It got to the point that I had to find a way to write down how it worked. Not the code itself, that's took hairy to look at and I'm a visual thinker so words are hard. I found myself tell VSCode many times that I wish it would draw me a map of what functions live in what component, where the states are being passed down from, which component is nested where ..... so I did that. I have easily spent half as much time taking note of all of this as I have actually writing code and troubleshooting code.

Here is what I came up with, and for anyone else that is a visual thinker like me I hope you find this helpful. I used mind mapping to build out the flow of the data, how the components connect and the logic of different aspects of the app. It doesn't matter the specific app I used as I'm not here to promote one useful app over another.

***Component Tree***
![Component Tree](https://dev-to-uploads.s3.amazonaws.com/i/ux0cf2s33knsy3r2rdph.png)

***Frontend Logic***
![Frontend Logic](https://dev-to-uploads.s3.amazonaws.com/i/aqnp9pnew383j4yjf9jt.png)

Here is a link to the full mind map, the above are just screen grabs of specific portions of the larger map. 
[Mind map](https://my.mindnode.com/njyMtZp4j4WydrpHks6vsbMTpCxmjWPX2vXf2xm4)

Thank you for reading this post, it was a longer one. Future posts on this project will hopefully be shorter.

Stay healthy :)