s_kajigo
@s_kajigo (kaji shogo)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

rails apiから取得したデータが一部取得できない

解決したいこと

フロントで、railsからのレスポンスデータのcurrent_userからログイン回数を取得したい。

reactとrails apiでポートフォリオ制作に挑戦しています。
認証機能にdevise,devise_token_authを使用しています。
今回初回ログインユーザに対してログイン後にポップアップを表示したく思い、deviseのtrackableの機能を使い,
sign_in_countが1のユーザーに対してフロントで条件分岐させようと試みていますが、レスポンスデータからログイン回数が取得できません。
以下のようにnameや自分で追加したカラムなどは取得できるのですが、sign_in_countがレスポンスに含まれておらず、どのようにrailsからフロントに渡せばいいのかがわからずつまずいています。

フロントで受け取ったレスポンスデータ
スクリーンショット 2022-09-29 11.33.43.png
データベースには正しくカラムが存在している
スクリーンショット 2022-09-29 11.47.07.png
データベースには正しく存在しているので、rails consoleでUser.find(1).sign_in_countとすると正しいログイン回数が取得できます。

以下、データの取得に関連すると思われる部分のコードです。

SignIn.jsx
export const SignIn = () => {
 const { setIsSignedIn, setCurrentUser, currentUser } = useContext(AuthContext);
 const [email, setEmail] = useState("");
 const [password, setPassword] = useState("");

 const history = useHistory();

 const generateParams = () => {
  const signInParams = {
   email: email,
   password: password,
  };
  return signInParams;
 };

 const handleSignInSubmit = async (e) => {
  e.preventDefault();
  const params = generateParams();
  try {
   const res = await signIn(params);
   if (res.status === 200) {
    Cookies.set("_access_token", res.headers["access-token"]);
    Cookies.set("_client", res.headers["client"]);
    Cookies.set("_uid", res.headers["uid"]);

    setIsSignedIn(true);
    setCurrentUser(res.data.data);
   }
  } catch (e) {
   console.log(e);
  }
 };
以下略
auth.js
import { client } from "./client";
import Cookies from "js-cookie";

// サインイン
export const signIn = (params) => {
 return client.post("/auth/sign_in", params);
};
//Cookie情報を送信して、対応するユーザー情報を返す
export const getCurrentUser = () => {
 if (
  !Cookies.get("_access_token") ||
  !Cookies.get("_client") ||
  !Cookies.get("_uid")
 )
  return console.log("ログイン中のユーザーはいません。");
 return (
  client.get("/auth/sessions", {
   headers: {
    "access-token": Cookies.get("_access_token"),
    "client": Cookies.get("_client"),
    "uid": Cookies.get("_uid"),
   },
  })
 )
};
sessions_controller.rb
class Api::V1::Auth::SessionsController < ApplicationController

 def index
     if current_api_v1_user
         render json: {status:200, current_user: current_api_v1_user }
     else
         render json: {status: 500, message: "ユーザーが存在しません"}
     end
 end
end

自分で試したこと

trackableの導入方法
current_userに含まれるデータは何なのか
trackableの活用方法
ログイン回数の取得方法
について検索しましたが、答えには辿り着けませんでした。

読みづらい質問かとは思いますが、ご教授いただけたら幸いです。

0

1Answer

【解決案1】
current_api_v1_userからjsonのパラメータを生成する処理を自作する
(例)

render json: {status:200, current_user: {
    name: current_api_v1_user.name,
    email: current_api_v1_user.email,
    .
    .
    .
    sign_in_count: current_api_v1_user.sign_in_count
  }
}

【解決案2】
そもそもuserに別カラム(初回ログイン済み/ポップアップ表示済み)を追加して管理する

【解決案3】

current_api_v1_user .as_json(:force_except => Devise::Models::Authenticatable::UNSAFE_ATTRIBUTES_FOR_SERIALIZATION.delete_if{|x| x == :sign_in_count}

この手法は以下の背景や具体的に何が行われているかを認識していない場合推奨しません。

【背景】
deviseで管理されたモデルをそのままJSONやxmlを返却すると以下のパラメータは返却されません。

UNSAFE_ATTRIBUTES_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
        :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
        :last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
        :remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]

※バージョンが古い場合、BLACKLIST_FOR_SERIALIZATIONという定数の可能性があります。
https://github.com/heartcombo/devise/blob/main/lib/devise/models/authenticatable.rb#L59

これはセキュリティ上の都合であり、noteのような事例を防ぐための機能です。
https://note.jp/n/n3e6451c9b147

1Like

Comments

  1. @s_kajigo

    Questioner

    大変わかりやすい回答をありがとうございます。
    1番の方法でやりたいことが実装できました!
    ただcurrent_api_v1_userで取得できる値とできない値がある理由までは辿り着けなかったので、また調べながら進めていきます。
    ありがとうございました!
  2. @s_kajigo

    Questioner

    失礼いたしました!!
    背景の部分にしっかりと理由を記載していただいてましたね(^_^;)
    改めてありがとうございました!

Your answer might help someone💌