##やりたいこと
現在バックエンドをrails -apiモード、フロントはreactでポートフォリオ を作成中です。
ログイン後に、再度ログインを保持する(current_userを確認する)機能を作成したいと思ってます。
しかし、logged_in?
のメソッドを実行した時に、
session[:user_id]がnilになってしまい、うまく@current_userに代入できません。
(ログイン時にはsession[:user_id]がしっかり入るのですが、logged_in?の時に消えてしまう。)
なぜsession[:user_id]がnilになってしまうのでしょうか?
(cookieは同じ値で飛んでいる気がします)
##試したこと
binding.pry
で以下のことを確認
applicationController
1def current_user 2 if session[:user_id] 3 @current_user ||= User.find_by(id: session[:user_id]) 4 end 5 binding.pry←ここにセット 6 end
irb
1[2] pry(#<Api::V1::SessionsController>)> session[:user_id] 2=> nil 3[3] pry(#<Api::V1::SessionsController>)> @current_user 4=> nil
##6/30追記
デバックツールで確認したところsessions_controller.application_controller共にメソッド自体は機能している模様ですが、
session[:user_id]はnilのままです。
cookieも同じ値が行っているのですが、sessionがうまくいきません。
##関連コード
sessionscontorller
1 2 3module Api 4 module V1 5 class SessionsController < ApplicationController 6 before_action :current_user, only: [:logged_in?] 7 8#loginでurl飛んできた後に実行するメソッド 9 def create 10 @user = User.find_by(email: session_params[:email]) 11 12 if @user && @user.authenticate(session_params[:password]) 13 login @user 14 render json: { 15 logged_in: true, 16 user: @user } 17 else 18 render json: { status: 401, errors: ['正しいメールアドレス・パスワードを入力して下さい' ] ,user: @user ,session:session{user_id}} 19 end 20 end 21 22#logged_inでurl飛んできた後に実行するメソッド 23 def logged_in? 24 if @current_user 25 render json: { logged_in: true, user: @current_user } 26 else 27 render json: { logged_in: false, errors: 'ユーザーが存在しません,ログインし直して下さい' } 28 end 29 end 30 31 private 32 33 def session_params 34 params.require(:user).permit(:email, :password) 35 end 36 end 37 end 38end
Applicationcontroller
1 2class ApplicationController < ActionController::API 3 include ActionController::Helpers 4 before_action :fake_load 5 skip_before_action :verify_authenticity_token, raise: false 6 # Railsが認証トークンを使用しないように 7 8 helper_method :login, :current_user 9 10 def login(user) 11 session[:user_id] = user.id 12 end 13 14 15 def current_user 16 if session[:user_id] 17 # @current_user ||= User.find(id: session[:user_id]) 18 @current_user ||= User.find(session[:user_id]) 19 end 20 end 21end
routes
1 2Rails.application.routes.draw do 3 namespace :api do 4 namespace :v1 do 5 root 'static_pages#home' 6 post '/signup', to: 'users#create' 7 8 post '/login',to:'sessions#create' 9 get '/logged_in', to: 'sessions#logged_in?' 10 delete '/logout',to:'sessions#logout' 11 12 resources :users 13 resources :recipes 14 15 end 16 end 17end
お手数ですが、どうすればsession[user_id]を取り出して@current_userにログイン中のuserを格納し、フロントへ返せるか教えていただけると幸いです。
https://railsguides.jp/action_controller_overview.html#%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3
##環境
・ローカル環境
・ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
・Rails 6.1.3.1
###前回の質問
https://teratail.com/questions/345569
##追加のコード
フロントエンド ログイン部のuseAuth
/* eslint-disable react-hooks/exhaustive-deps */ import { useCallback, useState } from "react"; import axios from "axios"; import { useHistory } from "react-router-dom"; import { useMessage } from "./useMessege"; import { useLoginUser } from "./useLoginUser" import { loginURL } from '../urls/index' export const useAuth = () => { const history = useHistory(); const { showMessage } = useMessage(); const { setLoginUser } = useLoginUser(); const [loading, setLoading] = useState(false); const login = useCallback((data) => { setLoading(true); //ローディングアイコンをtrueに axios.post(loginURL, { user: { email: data.email, password: data.password, } }, { withCredentials: true } ).then(response => { if (response.data.logged_in) { // contextにログインユーザーの情報を保存 setLoginUser(response.data) // handleSuccessfulAuth(response.data); showMessage({ title: "ログインしました", status: "success" }); history.push("/mypage"); // apiを叩き成功したらメソッドが起動し、data(userのデータ)をmypageに渡してページ遷移する } // 認証できなかった時のエラー else if (response.data.status === 401) { showMessage({ title: `${response.data.errors}`, status: "error" }); } // うまくpostできなかった時のエラー }).catch((e) => { showMessage({ title: "認証できませんでした。再度リロードなどを行いやり直して下さい", status: "error" }); setLoading(false); }) }, [history, showMessage, setLoginUser]); return { login, loading }; };
ログインをチェックするuseAuthCheck
/* eslint-disable react-hooks/exhaustive-deps */ import { useCallback } from "react" import axios from "axios"; import { useHistory } from "react-router-dom"; import { useMessage } from "./useMessege"; import { useLoginUser } from "./useLoginUser" import { logged_inURL } from '../urls/index' export const useAuthCheck = () => { const { setLoginUser } = useLoginUser(); const history = useHistory(); const { showMessage } = useMessage(); const CheckAuth = useCallback(() => { axios .get(logged_inURL,{ withCredentials: true }) .then(response => { if (response.data.logged_in === true) { setLoginUser(response.data.user) } // 認証できなかった時のエラー else if (response.data.logged_in === false) { showMessage({ title: `${response.data.errors}`, status: "error" }); history.push("/login"); console.log(response.data.session) console.log(response.data.user) } // うまくpostできなかった時のエラー }).catch((e) => { showMessage({ title: "再度送信して下さい", status: "error" }); }) }, []); return { CheckAuth }; }
sessions_store.rbでフロントエンドのドメインを変更し、cookieの保持は可能になりました。
if Rails.env === 'production' Rails.application.config.session_store :cookie_store, key: '_cooklog', domain: 'localhost3001' else Rails.application.config.session_store :cookie_store, key: '_cooklog' end
cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do # ローカル環境 allow do origins "http://localhost:3001" resource "*", headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head], credentials: true end end
ひたすらに詰まっております、、、わかる方がいらっしゃればご回答いただけると嬉しいです。。
回答1件
あなたの回答
tips
プレビュー