Rails/React persist user login

Viewed 20

I'm working on creating Login/Signup components using a Rails API and React as a frontend. I am able to login and display a homepage with the user and details.

I'm having some trouble though understanding how to persist that user's login and am definitely stuck in tutorial hell atm. Hoping someone could help me understand.

function App() {
  const API_BASE_URL = "http://localhost:3000/";
  const navigate = useNavigate();

  const [user, setUser] = useState(null);

  function whoAmI() {
    fetch(API_BASE_URL + "me").then((r) => {
      if (r.ok) {
        r.json().then((user) => {
          setUser(user);
        });
      }
    });
  }

  useEffect(() => {
    if (!user) {
      navigate("/login");
    } else {
      whoAmI();
      navigate("/");
    }
  }, [user, navigate]);

  return (
    <div className="App">
      <Routes>
        <Route
          path="/login"
          element={<Login API_BASE_URL={API_BASE_URL} onLogin={setUser} />}
        />
        <Route
          path="/"
          element={
            user ? (
              <Home user={user} />
            ) : (
              <Login API_BASE_URL={API_BASE_URL} onLogin={setUser} />
            )
          }
        />
      </Routes>
    </div>
  );
}

export default App;

So this is my app component I'm working with so far. I'm able to successfully handleLogin and console the user data. I keep getting this error though.

App.js:14 GET http://localhost:3000/me 401 (Unauthorized)

When I do backend testing I can post a login and then get /me but am missing the frontend translation I suppose.

Here is my application controller:

class ApplicationController < ActionController::API
  include ActionController::Cookies

  rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
  rescue_from ActiveRecord::RecordInvalid, with: :record_not_valid

  before_action :authorize

  private

  def authorize
    @current_user = User.find_by(id: session[:user_id])
    render json: { errors: ["Not authorized"] }, status: :unauthorized unless @current_user
  end

My sessions controller:

class SessionsController < ApplicationController
  skip_before_action :authorize, only: :login

  def login
    @user = User.find_by(username: params[:username])
    if @user&.authenticate(params[:password])
      session[:user_id] = @user.id
      render json: @user
    else
      render json: { errors: ["Invalid Username or Password"] }, status: :unauthorized
    end
  end

  def logout
    session.delete :user_id
    head :no_content
  end
end

And my users controller:

class UsersController < ApplicationController
  before_action :find_user, only: [:show, :destroy, :update]
  skip_before_action :authorize, only: [:create]

  def index
    render json: User.all, adapter: nil,
           except: creation_ref, status: :ok
  end

  def show
    render json: @current_user, status: :ok
  end

  # def whoami
  #   render json: @current_user, status: :ok
  # end

  def create
    @user = User.create!(user_params)
    session[:user_id] = @user.id
    render json: @user, status: :created
  end

  def update
    @user.update!(user_params)
    render json: @user, status: :ok
  end

  def destroy
    @user.destroy
    head :no_content
  end

  private

  def user_params
    params.permit(:username, :password, :image_url, :bio)
  end

  def find_user
    @user = User.find(params[:id])
    !@user ? record_not_found(@user) : @user
  end
end

Finally my routes

Rails.application.routes.draw do
  post "/signup", to: "users#create"
  get "/me", to: "users#show"
  post "/login", to: "sessions#login"
  delete "/logout", to: "sessions#logout"
  resources :pokemons
  resources :users
end

This is meant to be practice to figure out auth and persisting users for use in an upcoming project I'm planning.

My thoughts so far: I'm not actually saving the user's session.id anywhere and that could be a missing link? I thought with sessions it was automatically stored in localStorage and was the advantage over using JWT.

I'm not putting a proper check / or using incorrect syntax in the get request to the /me route.

Any and all help is greatly appreciated!

If I can post anything additional please let me know, as well as if there are other posts covering this topic that I was unable to find I would love the references! Thanks all!

0 Answers
Related