LoginSignup
3
0

More than 3 years have passed since last update.

[graphql-ruby] [ActionCableSubscriptions] subscriptionをtriggerする際に、送るオブジェクトが独自のクラスの場合

Last updated at Posted at 2020-03-28

問題

HashOpenStructActiveRecordでない、独自のクラスを下のよう感じでtriggerした場合

AppSchema.subscriptions.trigger(
  "your_subscription_name",
  { },
  {
    users: users,
  }
)

このようなエラーが出る

There was an exception - RuntimeError(        Failed to implement User.id, tried:

        - `Types::UserType#id`, which did not exist
        - `String#id`, which did not exist
        - Looking up hash key `:id` or `"id"` on `#<User:0x000055a03c518290>`, but it wasn't a Hash

        To implement this field, define one of the methods above (and check for typos)
)

原因

渡したオブジェクトがHashっぽくないって事でエラーになっている様子
しかしながら、全く同じオブジェクトをsubscriptionの最初の呼び出しの際に渡しても、それは正常に送ってくれる ...

module Subscriptions
  class YourSubscriptionName < GraphQL::Schema::Subscription

    field :users, [Types::UserType], null: false
    def subscribe)
      users = ...

      # これはなぜか問題ない
      {
        users: users
      }
    end
  end
end

解決方法

issueに上がっていた内容

  1. 独自クラスにGlobalIDを埋め込む
  2. Subscriptionの宣言時に、独自のserializerを設定する

方法1

GlobalIDを使って下のようにメソッドを増やす
*データベース絡みじゃない特殊なケースはIDをjsonデータなどにして、findの時に渡されるid(自分が先に設定したjson)をパースするなどの工夫も出来る(らしい)

# activerecordでない、独自のクラス
class User
  include GlobalID::Identification

  # 最低でも id、==、self.findが必要
  attr_reader :id

  def initialize(id)
    @id = id
  end

  def self.find(id)
    # どうにかこうにかデータを持ってくる
    User.new(id)
  end

  def ==(that)
    self.id == that.id
  end
end

方法2

subscriptionのクラスを宣言する際にserializerを設定する ... らしい


class AppSchema < GraphQL::Schema
  # 通常はこう
  # use GraphQL::Subscriptions::ActionCableSubscriptions

  use GraphQL::Subscriptions::ActionCableSubscriptions.new(serializer: YourSerialize)
3
0
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0