DEV Community

loading...

Flatiron Final Project - Rails API, React-Redux

mmcclure11 profile image MMcClure11 ・3 min read

For my final Flatiron project I decided to make a Nature Watch app where users can signup, login, logout, create entries of sightings of Flora and Fauna they'd seen in nature, and view what other users had added and chosen to make public.

One of the issues that I ran into that took a lot of troubleshooting, console.logging and using debugger was getting users to Logout appropriately. If a user was on the home page and clicked the logout button, my currentUser in the redux store was successfully cleared out. However the issue was that when clicking the logout when NOT on the home page, I had set it up so that the user was redirected to the home page, which happened successfully, but then the user was not actually logged out.

Logout.js

import React from 'react'
import { connect } from 'react-redux'
import { logout } from "../actions/currentUser.js"
import { withRouter } from 'react-router-dom'

const Logout = ({ logout, history }) => {
  return (
    <form onSubmit={(event) => {
        event.preventDefault()
        logout()
        history.push('/')
      }
    }>
      <input className='btn btn--small' type="submit" value="Log Out"/>
    </form>
  )
}

export default withRouter(connect(null, { logout } )(Logout))
Enter fullscreen mode Exit fullscreen mode

I knew this had something to do with the fact that I was using a component did mount to get the set the currentUser in the redux store and access that data on the home page. So my first solution was to redirect the user to a page that did not invoke componentDidMount, such as the login page.

Logout.js

import React from 'react'
import { connect } from 'react-redux'
import { logout } from "../actions/currentUser.js"
import { withRouter } from 'react-router-dom'

const Logout = ({ logout, history }) => {
  return (
    <form onSubmit={(event) => {
        event.preventDefault()
        logout()
        history.push('/login')
      }
    }>
      <input className='btn btn--small' type="submit" value="Log Out"/>
    </form>
  )
}

export default withRouter(connect(null, { logout } )(Logout))
Enter fullscreen mode Exit fullscreen mode

This worked, but I was not wholly satisfied with not understanding between my backend, react and redux. After quite a bit more time spent trying to understand what was happening, I finally had that aha! moment. I had forgotten a key part of the asynchronous dispatches in the fetch request. I was trying to history.push('/') inside onClick of Logout and because the fetch to the backend to clear the session[:user_id] was happening after the history.push('/'), the session[:user_id] wasn't being cleared out before the componentDidMount was invoking get_current_user and grabbing that user. Once this was clear to me I knew I had to change when the redirect to the home page was happening. The best place for that was in my action creator for logging out after the session had been cleared. By passing the history into the action creator I was able to push the home page into the history after fetch completed logout so when the componentDidMount ran on the home page the session was empty and the get_current_user returned null so the user successfully stayed logged out.

Logout.js

import React from 'react'
import { connect } from 'react-redux'
import { logout } from "../actions/currentUser.js"
import { withRouter } from 'react-router-dom'

const Logout = ({ logout, history }) => {
  return (
    <form onSubmit={(event) => {
        event.preventDefault()
        logout(history)
      }
    }>
      <input className='btn btn--small' type="submit" value="Log Out"/>
    </form>
  )
}

export default withRouter(connect(null, { logout } )(Logout))
Enter fullscreen mode Exit fullscreen mode

'.actions/currentUser.js'

export function logout(history) {
  return dispatch => {
    return fetch('http://localhost:3000/api/v1/logout', {
      credentials: "include",
      method: "DELETE"
    })
    .then(resp => resp.json())
    .then(() => {
      dispatch({type: 'CLEAR_CURRENT_USER'})
      history.push('/')
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

SessionsController

def destroy
    session.delete :user_id
    if !session[:user_id]
      render json: {
        notice: "successfully logged out"
      }, status: :ok
    else
      render json: {
        error: "Unsuccessful log out"
      }
    end
  end
Enter fullscreen mode Exit fullscreen mode

This project stretched my knowledge in a lot of ways and I'm pretty proud of myself for how far I've come and the improvement I've seen in my code.

Check out the front end here: https://github.com/MMcClure11/sightings-client
and the back end here: https://github.com/MMcClure11/sightings-api.

Cheers and happy coding!

Discussion (0)

pic
Editor guide