Rails Action Cable+GraphQL Apollo订阅报错:查询参数应为字符串
Rails GraphQL订阅报错:Query string argument should be a String, got Hash instead.
问题场景
使用Rails 6.1的graphql gem搭配Apollo实现GraphQL订阅,普通查询、突变功能正常,但触发订阅时后端抛出错误。前端通过ActionCable创建连接并使用ActionCableLink,后端GraphqlChannel的execute方法日志显示query为String类型,却收到报错:「查询字符串参数应为String,实际为Hash」。
相关代码片段
前端ActionCable连接代码
const cable = ActionCable.createConsumer( `${process.env.GATSBY_CABLE_URL}/cable?token=${localStorage.getItem('apiToken')}`, ); const actionCableLink = new ActionCableLink({ cable });
后端GraphqlChannel核心代码
class GraphqlChannel < ApplicationCable::Channel def execute(data) query = data['query'] variables = ensure_hash(data['variables']) operation_name = data['operationName'] context = { channel: self } # 此处为错误调用方式 result = ContentManagementSchema.execute({ query: query, context: context, variables: variables, operation_name: operation_name }) # ... 后续逻辑 end # ... 其他方法 end
Rails控制台报错
Executing PageComments 9:51:43 AM web.1 | executing schema query is a String 9:51:43 AM web.1 | Error in graphql channel: Query string argument should be a String, got Hash instead. - Op: SchedulePublishingStatus 9:51:43 AM web.1 | Error in graphql channel: Query string argument should be a String, got Hash instead. - Op: PageComments
前端订阅代码
const { loading, error: subscriptionError } = useSubscription(PAGE_COMMENTS, { variables: { pageId }, onSubscriptionData: (res) => { setComments(res.subscriptionData.data.pageComments); }, });
GraphQL订阅定义
export const PAGE_COMMENTS = gql` subscription PageComments($pageId: ID) { pageComments(pageId: $pageId) { id body createdAt user { id email } } } `;
问题原因
报错的核心是**ContentManagementSchema.execute的调用方式错误**:Rails graphql gem的execute方法要求第一个参数为String类型的查询字符串,后续参数为可选的关键字参数(如context、variables等)。当前代码把所有参数打包成一个Hash传入,导致gem将整个Hash识别为query参数,从而触发类型不匹配错误。
修复方案
修改GraphqlChannel#execute方法中调用execute的代码,将参数拆分为单独的查询字符串和关键字参数:
方案一:直接传递位置参数+关键字参数
result = ContentManagementSchema.execute( query, context: context, variables: variables, operation_name: operation_name )
方案二:使用关键字参数展开(适用于参数较多的场景)
execute_params = { query: query, context: context, variables: variables, operation_name: operation_name } result = ContentManagementSchema.execute(**execute_params)
验证
修改后重启Rails服务,触发订阅请求,后端将正确解析String类型的query参数,不再抛出类型不匹配的错误,订阅功能可正常工作。
内容的提问来源于stack exchange,提问作者bnassler
相关产品推荐
相关产品推荐

