You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GithubGraphqlService中动态访问@access_token配置GraphQL请求头

如何在GraphQL::Client::HTTP的headers方法中访问外部类的实例变量?

我编写了如下GithubGraphqlService类,尝试在GraphQL::Client::HTTP的headers方法中访问类的@access_token实例变量,但直接调用会提示未定义:

class GithubGraphqlService
  URL = "https://api.github.com/graphql".freeze
  attr_reader :access_token
  
  def initialize(access_token)
    @access_token = access_token
  end

  def client
    http_adapter ||= GraphQL::Client::HTTP.new(URL) do
      def headers(_context)
        {
          "Authorization" => "Bearer #{access_token}", # access_token is undefined
          "User-Agent" => "Ruby"
        }
      end
    end

    schema ||= GraphQL::Client.load_schema(http_adapter)
    @_client ||= GraphQL::Client.new(schema:, execute: http_adapter)
  end
end

我尝试了两种修复方案,但均无效:

无效修复方案1

直接使用实例变量@access_token,但结果为nil:

def client
    http_adapter ||= GraphQL::Client::HTTP.new(URL) do
      def headers(_context)
        {
          "Authorization" => "Bearer #{@access_token}", # @access_token is nil
          "User-Agent" => "Ruby"
        }
      end
    end

    schema ||= GraphQL::Client.load_schema(http_adapter)
    @_client ||= GraphQL::Client.new(schema:, execute: http_adapter)
end

无效修复方案2

将实例变量赋值给局部变量后调用,仍提示未定义:

def client
    github_access_token = @access_token
    http_adapter ||= GraphQL::Client::HTTP.new(URL) do
      def headers(_context)
        {
          "Authorization" => "Bearer #{github_access_token}", # github_access_token is undefined
          "User-Agent" => "Ruby"
        }
      end
    end

    schema ||= GraphQL::Client.load_schema(http_adapter)
    @_client ||= GraphQL::Client.new(schema:, execute: http_adapter)
end

问题核心:headers方法定义在GraphQL::Client::HTTP子类的上下文中,无法直接访问GithubGraphqlService的实例变量@access_token。


正确解决方法

利用Ruby的闭包特性,使用define_method替代def来定义headers方法,这样可以捕获外部作用域的局部变量:

class GithubGraphqlService
  URL = "https://api.github.com/graphql".freeze
  attr_reader :access_token
  
  def initialize(access_token)
    @access_token = access_token
  end

  def client
    # 先将实例变量赋值给局部变量,让闭包可以捕获
    token = @access_token
    http_adapter ||= GraphQL::Client::HTTP.new(URL) do
      # 使用define_method定义headers方法,能捕获外部的token变量
      define_method :headers do |_context|
        {
          "Authorization" => "Bearer #{token}",
          "User-Agent" => "Ruby"
        }
      end
    end

    schema ||= GraphQL::Client.load_schema(http_adapter)
    @_client ||= GraphQL::Client.new(schema:, execute: http_adapter)
  end
end

原理说明

  • do...end块是用来创建GraphQL::Client::HTTP的子类,内部用def定义的方法作用域属于这个子类,无法访问外部类的实例变量。
  • define_method是在当前块的作用域中执行,能够捕获块外部的局部变量(比如这里的token),因此headers方法可以正常访问到access_token的值。

内容的提问来源于stack exchange,提问作者Anmol Shrivastav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 21:12:45