やる事
-
graphql-ruby
でDataloader
を使用する宣言 -
Dataloader
はmodel
のassociations
を事前読み込みする処理を実装 - 実装した
Dataloader
をType
クラスで仕様します
1. graphql-ruby
でDataloader
を使用する宣言
app_schema.rb
でdataloader
を有効化します。
app/graphql/app_schema.rb
class AppSchema < GraphQL::Schema
+ use GraphQL::Dataloader
disable_introspection_entry_points unless Rails.env.development?
query(QueryType)
max_complexity 200
max_depth 30
default_page_size 50
validate_max_errors 100
end
2. Dataloader
はmodel
のassociations
を事前読み込みする処理を実装
graphql-batch
gemのリポジトリにActiveRecord
のPreloader
を扱うサンプルがあったので参考に以下のようにgraphql-ruby
が提供しているdataloader
機能で実装します
app/graphql/active_record_preloader.rb
# frozen_string_literal: true
class ActiveRecordPreloader < GraphQL::Dataloader::Source
attr_reader :model, :association
def initialize(model, association)
@model = model
@association = association
end
def fetch(records)
validate!(records)
::ActiveRecord::Associations::Preloader.new(records:, associations: association).call
records.map { |record| record.public_send(association) }
end
private
def validate!(records)
raise TypeError, "loader can't load association for #{model}" unless records.all? { |r| r.is_a?(model) }
return if model.reflect_on_association(association)
raise ArgumentError, "No association #{association} on #{model}"
end
end
3. 実装したDataloader
をType
クラスで仕様します
以下のように、dataloader.with
メソッドの引数に
- 作成した
ActiveRecordPreloader
-
ActiveRecord
のmodel
-
model
に紐づくpreload
したいassociation
を指定します
app/graphql/user_type.rb
class UserType < Types::BaseObject
field :email, String, null: false
field :user_post, UserPostType, null: false
def profile
dataloader.with(ActiveRecordPreloader, ::User, :user_post).load(object)
end
end
参考
- https://graphql-ruby.org/dataloader/dataloader.html
- https://graphql-ruby.org/dataloader/adopting.html#comparison-fetching-objects-in-sequence-dependent
環境
- ruby 3.2.2
- rails 7.0.8
- graphql 2.1.0