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!