无法在 devise 中使用帮助程序方法“current_user”

Cannot use the helper method `current_user` in devise

提问人:Tsubasa 提问时间:10/27/2023 最后编辑:Tsubasa 更新时间:10/28/2023 访问量:47

问:

我正在使用 nextjs 和 rails 构建一个简单的待办事项应用程序。 我正在使用 devise 进行用户身份验证,但我不能使用 current_user。 具体来说,我正在使用 JSON API 序列化程序在登录期间以 JSON 格式将用户信息返回到前面。这是轨道布线。

routes.rb

Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  root to: 'health_check#index'

  devise_for :users, skip: %w[registrations sessions]
  devise_scope :user do
    namespace :api do
      namespace :v1 do
        resource :current_user, controller: 'devise/current_user', only: %i[show]
        resource :user_sessions, controller: 'devise/user_sessions', only: %i[create destroy]
        resources :users, controller: 'devise/users' , only: %i[create]
      end
    end
  end
end

以下是 api/v1/devise/current_user_controller.rb

# frozen_string_literal: true

module Api
  module V1
    module Devise
      class CurrentUserController < ApplicationController
        module Consts
          RESP_FIELDS = %i[id email name].map(&:freeze).freeze

          Consts.freeze
        end

        def show
          with_rescue(__method__) do
            render json: current_user_serializable_hash.to_json, status: :ok
          end
        end

        private

        def current_user_serializable_hash
          UserSerializer.new(current_user, { fields: { user: Consts::RESP_FIELDS } }).serializable_hash
        end
      end
    end
  end
end

控制器/application_controller.rb

# frozen_string_literal: true

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

这里是 app/serializers/user_serializer.rb

# == Schema Information
#
# Table name: users
#
#  id                     :bigint           not null, primary key
#  email                  :string(255)      default(""), not null
#  name                   :string(255)      not null
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#
# Indexes
#
#  index_users_on_email                 (email) UNIQUE
#  index_users_on_name                  (name)
#
class UserSerializer < BaseSerializer
  attributes :id, :email, :name
end

base_serializer.rb

# frozen_string_literal: true

class BaseSerializer
  include JSONAPI::Serializer

  set_key_transform :camel_lower
end

错误如下 返回到前面的 JSON 的值为 null。

{"data":null}

但是,为了隔离问题,我在current_user_controller中将current_user_serializable_hash方法更改为此方法。

def current_user_serializable_hash
  UserSerializer.new(current_user, { fields: { user: Consts::RESP_FIELDS } }).serializable_hash
end
↓
def current_user_serializable_hash
  UserSerializer.new(User.find(1), { fields: { user: Consts::RESP_FIELDS } }).serializable_hash
end

然后以 JSON 格式返回响应,如下所示。

{
    "data": {
        "id": "1",
        "type": "user",
        "attributes": {
            "id": 1,
            "email": "[email protected]",
            "name": "hoge1"
        }
    }
}

换句话说,current_user方法不起作用。我想知道为什么。我不知道。有谁知道发生了什么?谢谢。

附言----------------------------------

我在正文中添加了部分用于登录的user_sessions_controller代码。

# frozen_string_literal: true
module Api
  module V1
    module Devise
      class UserSessionsController < ApplicationController

        def create
          with_rescue(__method__) do
            user = User.find_for_authentication(email: user_session_params[:email])
            raise ApplicationController::UnauthorizedError, 'email' if user.blank?

            is_success = user&.valid_password?(user_session_params[:password])
            raise ApplicationController::UnauthorizedError, 'password' unless is_success

            bypass_sign_in(user)
            head :no_content
          end
        end
JSON Ruby-on-Rails Ruby 序列化 设计

评论

1赞 dbugger 10/27/2023
current_user为 null,因为用户未登录。默认情况下,Rails API 不使用 cookie,因此没有会话机制来存储登录用户。通常,当使用 rails 作为 api 时,您需要登录,获取令牌并将其传递给前端,然后在来自前端的所有后续请求中使用该令牌。rails api 对令牌进行解码并设置用户。
0赞 user229044 10/28/2023
随机的东西,但不要把你的常量放在它们自己的模块中。你不应该这样做,就像你把你的类放在它们自己的模块中,或者把你的变量放在一个模块中一样。ConstsClassesVars
0赞 Tsubasa 10/28/2023
致 dbugger,感谢您的评论。我们通过登录行为将会话信息存储在 redis 中。我在正文中添加了部分用于登录的user_sessions_controller代码。这些已被证实有效。

答:

-1赞 Tsubasa 10/28/2023 #1

我自己解决了这个问题。 具体来说,我将以下内容添加到config/environments/development.rb

config.cache_store = :redis_cache_store, { expires_in: 7.days, # TODO: 仮設定
                                               namespace: "#{Rails.application.class.module_parent_name.downcase}:#{
                                                   (ENV.fetch('RAILS_ENV', 'development') + ':').then.detect { |e| e != 'production:' }
                                                 }cache",
                                               url: "redis://#{ENV.fetch('REDIS_HOST', 'localhost')}:#{ENV.fetch('REDIS_PORT', '6379')}/0" }

    config.public_file_server.headers = {
      'Cache-Control' => "public, max-age=#{2.days.to_i}"
    }

谢谢。

评论

0赞 Mike Szyndel 10/31/2023
你打算在这个片段中做什么?(ENV.fetch('RAILS_ENV', 'development') + ':').then.detect { |e| e != 'production:' }