首页 > 解决方案 > ruby-graphql 和/或 actioncable 转储“核心”订阅

问题描述

在这里远射,但想知道是否有人可以解释为什么从 react (17.1) 到 Rails (6.1.1) 和 graphql (1.12) API 订阅 @apollo/client (3.3.11) 会导致 Rails 发生什么我只能形容为“转储核心”(对不起,我是一个老家伙)。

外部症状是,当客户端连接时,我会得到以以下开头的页面和日志页面:

Started GET "/cable/" [WebSocket] for 172.27.0.1 at 2021-03-30 19:30:45 +0000
api_1  | Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
api_1  | GraphqlChannel is transmitting the subscription confirmation
api_1  | GraphqlChannel is transmitting the subscription confirmation
api_1  | GraphqlChannel#execute({"query"=>"subscription {\n  commentAdded {\n    id\n    title\n    __typename\n  }\n}\n", "variables"=>{}})
api_1  | GraphqlChannel#execute({"query"=>"subscription {\n  commentAdded {\n    id\n    title\n    __typename\n  }\n}\n", "variables"=>{}})
api_1  | Could not execute command from ({"command"=>"message", "identifier"=>"{\"channel\":\"GraphqlChannel\",\"channelId\":\"1788483aa6e\"}", "data"=>"{\"query\":\"subscription {\\n  commentAdded {\\n    id\\n    title\\n    __typename\\n  }\\n}\\n\",\"variables\":{},\"action\":\"execute\"}"}) 
[NoMethodError - undefined method `unpack' for {:query=>"subscription {\n  commentAdded {\n    id\n    title\n    __typename\n  }\n}\n", :context=>{:channel=>#<GraphqlChannel:0x000055b35c0503b0 @connection=#<ApplicationCable::Connection:0x000055b35c1b1308 @coder=ActiveSupport::JSON, 
@env={"rack.version"=>[1, 6], "rack.errors"=>#<IO:<STDERR>>, "rack.multithread"=>true, "rack.multiprocess"=>false, "rack.run_once"=>false, 
"SCRIPT_NAME"=>"/cable", "QUERY_STRING"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"puma 5.2.2 Fettisdagsbulle", "GATEWAY_INTERFACE"=>"CGI/1.2", "REQUEST_METHOD"=>"GET", "REQUEST_PATH"=>"/cable", 
"REQUEST_URI"=>"/cable", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_HOST"=>"localhost:3001"...

然后继续列出与我的计算机、文件、应用程序的状态有关的任何事情,重复……很多。

因此,正常的查询和突变工作正常。订阅在 graphiql 中是可见的,事实上,鉴于我看到的事实:

[ActionCable] Broadcasting to graphql-event::commentAdded:: "{\"__gid__\":\"Z2lkOi8va29hbGEtYXBpL0NvbW1lbnQvZjQzNWQyOWUtODMxOC00YWY0LTg5ODktZDJiZDhkOTljYmQ4\"}"

在我的 Rails 日志中,我认为大部分工作都在 Rails 内部进行。(例如,如果我更改订阅名称,则会出错。电缆连接似乎在某种程度上已经建立,因为我在 Chrome 开发工具中看到了 ping。)

但是,更新永远不会发送到客户端。

gql 看起来像:

const COMMENTS_SUBSCRIPTION = gql`
  subscription {
    commentAdded {
      id
      title
    }
  }
`;

像这样设置 Apollo 客户端(相关部分,如可用的几个文档中所示):

const link = ApolloLink.split(
  hasSubscriptionOperation,
  new ActionCableLink({cable}) as any,
  stdLink
);

并且订阅在 Rails 中设置,如下所示:

module Types
  class SubscriptionType < GraphQL::Schema::Object
    field :comment_added, type: Types::CommentType,
                          null: false,
                          description: "Subscription to push new comments as added"

    def comment_added
      object
    end
  end
end

一旦发生了 Big Barf,它就会接受突变,添加东西,记录它正在广播,然后……什么都没有。客户端上没有任何迹象。这让我相信订阅实际上并没有注册。

关于寻找什么的任何指示?我应该能够以某种方式从 Rails 控制台进行调试吗?

标签: ruby-on-railsgraphqlapollo-clientreact-apollo

解决方案


好的,为了回答我自己的问题,这是按照最重要的一步一步列出的graphql 订阅栏的结果,这些栏将保持无名。它建议按如下方式设置频道:

result = GraphqlRailsApiSchema.execute({
      query: query,
      context: context,
      variables: variables,
      operation_name: operation_name
    })

现在我知道了。不要那样做。注意整个参数是一个哈希。深入研究 graphql gem 源代码,我看到它需要一个查询字符串和**kwargs. 简而言之,它采用该哈希并将其视为查询字符串参数(因此,尝试使用unpack它)。

相反,您可以这样做:

result = GraphqlRailsApiSchema.execute(
      query,
      context: context,
      variables: variables,
      operation_name: operation_name
    )

“小心你在网上看到的内容。” ——苏格拉底


推荐阅读