如何在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
相关产品推荐
相关产品推荐

