問題
Hash
、OpenStruct
、ActiveRecord
でない、独自のクラスを下のよう感じで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に上がっていた内容
- 独自クラスにGlobalIDを埋め込む
- 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)