LoginSignup
s_kajigo
@s_kajigo (kaji shogo)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

rails devise_token_auth ActionDispatch::Cookies::CookieOverflow について

解決したいこと

ActionDispatch::Cookies::CookieOverflow を解決したい。
サインインのたびにtokenがdbに追加されてしまうことを解決したい。

現在Rails6.1、React17.0.2でログイン機能を学習中です。
devise,devise_token_authを使用してトークンベースでの認証を目指しています。
こちらの記事(https://zenn.dev/shogo_matsumoto/articles/c6485b39c5f621#4.-%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E6%A9%9F%E8%83%BD%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%82%92%E5%A4%89%E6%9B%B4)
を参考に、サインアップ、メール認証を行うことはできたのですが、何度かサインインを行うと、
ActionDispatch::Cookies::CookieOverflow (ActionDispatch::Cookies::CookieOverflow):
のエラーが表示され、バックエンドとの以降の通信がエラーとなるようになってしまいました。

エラーについて調べ、Cookie容量がオーバーしていることが原因だとわかりました。
googleデベロッパーツールにて、Cookieを確認すると、
スクリーンショット 2022-09-26 21.31.28.png
このように表示されておりましたが、データーベースを確認したところ、
スクリーンショット 2022-09-26 21.21.40.png
tokensカラムのデータがサインインするたびに追加されていることがわかりました。
これがエラーの原因ではないかと予測しているのですが、解決には至らずにいます。

今回記載したコードは 以下の通りです。

フロント側

App.js
import { createContext, useEffect, useState } from "react";
import { BrowserRouter, Switch, Route, Redirect } from "react-router-dom";
import { getCurrentUser } from "./api/auth";
import { Home } from "./components/Home";
import { SignIn } from "./components/SignIn";
import { SignUp } from "./components/SignUp";

export const AuthContext = createContext();

function App() {
  const [loading, setLoading] = useState(true);
  const [isSignedIn, setIsSignedIn] = useState(false);
  const [currentUser, setCurrentUser] = useState();

  // Cookieからログイン中ユーザーを取得、結果をハンドリング、最後にloadingをfalseに
  const handleGetCurrentUser = async () => {
    try {
      const res = await getCurrentUser();
      if (res?.data.isLogin === true) {
        setIsSignedIn(true);
        setCurrentUser(res?.data.currentUser);
      } else {
        console.log("no current user");
      }
    } catch (e) {
      console.log(e);
    }
    setLoading(false);
  };

  //初回レンダリング、currentUserstateの変更時にユーザーを取得しにいく。
  useEffect(() => {
    handleGetCurrentUser();
  }, [currentUser]);

  const Private = ({ children }) => {
    if (!loading) {
      if (isSignedIn) {
        return children;
      } else {
        return <Redirect to="/signin" />;
      }
    } else {
      return <></>;
    }
  };
  return (
    <AuthContext.Provider
      value={{
        loading,
        setLoading,
        isSignedIn,
        setIsSignedIn,
        currentUser,
        setCurrentUser,
      }}
    >
      <BrowserRouter>
        <Switch>
          <Route exact path="/signup">
            <SignUp />
          </Route>
          <Route exact path="/signin">
            <SignIn />
          </Route>
          <Private>
            <Route exact path="/">
              <Home />
            </Route>
          </Private>
        </Switch>
      </BrowserRouter>
    </AuthContext.Provider>
  );
}

export default App;

auth.js
import { client } from "./client";
import Cookies from "js-cookie";

// サインアップ
export const signUp = (params) => {
 return client.post("/auth", params);
};

// サインイン
export const signIn = (params) => {
 return client.post("/auth/sign_in", params);
};

// サインアウト
export const signOut = () => {
 return client.delete("/auth/sign_out", {
  headers: {
   "access-token": Cookies.get("_access_token"),
   client: Cookies.get("_client"),
   uid: Cookies.get("_uid"),
  },
 });
};

export const getCurrentUser = () => {
 if (
  !Cookies.get("_access_token") ||
  !Cookies.get("_client") ||
  !Cookies.get("_uid")
 )
  return 
 return (
  client.get("/auth/sessions", {
   headers: {
    "access-token": Cookies.get("_access_token"),
    "client": Cookies.get("_client"),
    "uid": Cookies.get("_uid"),
   },
  })
 )
};


バックエンド側

該当するソースコード

auth/session_controller.rb
class Api::V1::Auth::SessionsController < ApplicationController

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

例)

initializer/devise_token_auth.rb
DeviseTokenAuth.setup do |config|

  config.change_headers_on_each_request = false
  config.token_lifespan = 2.weeks
  config.token_cost = Rails.env.test? ? 4 : 10
  config.max_number_of_devices = 2

  config.headers_names = {:'access-token' => 'access-token',
                         :'client' => 'client',
                         :'expiry' => 'expiry',
                         :'uid' => 'uid',
                         :'token-type' => 'token-type',
                         :'authorization' => 'authorization' }

end
config/application.rb
require_relative "boot"

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_mailbox/engine"
require "action_text/engine"
require "action_view/railtie"
require "action_cable/engine"
# require "sprockets/railtie"
require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Myapp
  class Application < Rails::Application
    config.load_defaults 6.1

    config.i18n.default_locale = :ja
    config.api_only = true

    config.session_store :cookie_store, key: '_interslice_session'
    config.middleware.use ActionDispatch::Cookies
    config.middleware.use ActionDispatch::Session::CookieStore, config.session_options
    config.middleware.use ActionDispatch::Flash
    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins 'localhost:8000'
        resource '*',
                 :headers => :any,
                 :expose => ['access-token', 'expiry', 'token-type', 'uid', 'client'],
                 :methods => [:get, :post, :options, :delete, :put]
      end
    end
  end
end

大変お見苦しいコードかとは思いますが、ご教授いただけたら幸いです。
記載が足りないファイル等ありましたらご指摘いただけるとありがたいです。

0

2Answer

config.session_store :cookie_store, key: '_interslice_session'

これを active_record_store に変えるとかですかね?

1

Comments

  1. @s_kajigo

    Questioner
    回答ありがとうございます。active_recordはなるべく選ばないとの記事を見たので、できればcookieを使用して通信を小ないたいのですが難しいのでしょうかか?
  2. なるほど…

    ちなみに通信ではなくてセッションに格納されたデータ量の問題ではないんでしょうか

tokensカラムのデータがサインインするたびに追加されていることがわかりました。
これがエラーの原因ではないかと予測しているのですが、解決には至らずにいます。

usersテーブルのレコードが増えていくってことでしょうか?
sessionのデータとは関係ない気もするんですが

1

Comments

  1. @s_kajigo

    Questioner
    なるほど確かにおっしゃる通りかと思いました。
    詳しい原因はわからなかったものの、一応問題が解決したのでご報告しておきます。
    application.rbの記述のconfig.api_only = true以下を
    config.middleware.use ActionDispatch::Flashのみに変更し、corsの設定を別ファイルにしたらなぜかうまくいきました。rails内部の仕組みをほとんど知らない状態だったのでこれを機に勉強していこうと思います!
    また、active_recordでの管理の仕方についても勉強する機会となりました。ご回答いただきありがとうございました!
  2. ちょっと根本原因が分からないですが解決したようで良かったです!

Your answer might help someone💌