【Rails × GraphQL 入門】contextとfind_byの使い分け具体例を用いて解説
context
と find_by
の適切な使い分け
Rails アプリケーションで GraphQL を導入すると、データ取得に find_by
と context
の2つの方法が使えます。どちらを使うかの判断はシンプルですが、適切な使い分けが開発の効率性を左右します。本記事では両者の特徴を掘り下げ、具体的なコード例を交えながらその判断基準を明確にします。
なお、ここでの内容は筆者の経験に基づく個人的な見解であり、環境やユースケースによって認識の齟齬や誤りがある場合があります。その点をご了承ください。
find_by
と context
の違い
まず、それぞれの基本的な特徴を再確認しましょう。
find_by
の特徴
- 指定した条件に基づきデータベースを直接検索
- キャッシュを使わず毎回クエリを実行
- レコードが存在しない場合は
nil
を返す - モデル間のリレーションがなくても動作可能
context
の特徴
- GraphQL のリクエスト全体で共有される一時的なデータ
- 一般的に
context[:current_user]
で認証情報を保持 - 一度取得したデータを複数のクエリで再利用可能で不要な DB アクセスを回避
- ユーザーに紐づくリレーションの取得に特に適している
context
を使うべき具体的なケース
ログインしているユーザーに関連するデータを頻繁に取得する場合、context
は最適です。
app/graphql/types/auth_query_type.rb
)
コード例(ファイル: module Auth
module Types
class AuthQueryType < Base::Types::BaseObject
field :user_profile, Auth::Types::ProfileType, null: false,
description: "現在のログインユーザーのプロフィールを取得します。"
def user_profile
context[:current_user].profile # リレーション経由で効率よく取得
end
end
end
end
ここで重要なのは、context[:current_user]
を使うことにより、ユーザーのプロフィールを直接取得できます。これにより、不要な DB クエリが発生しない点です。これは特にパフォーマンスに敏感な環境で効果的です。
find_by
を使うべき具体的なケース
一方、特定の条件に基づくデータ取得を行う場合には find_by
を使用します。
app/graphql/types/auth_query_type.rb
)
コード例(ファイル: module Auth
module Types
class AuthQueryType < Base::Types::BaseObject
field :post, Auth::Types::PostType, null: false do
argument :id, ID, required: true
end
def post(id:)
Post.find_by!(id: id, user_id: context[:current_user].id) # 特定の条件を指定して検索
end
end
end
end
ここでは id
と user_id
を条件として指定しています。find_by
はリレーション経由だけでは絞り込みが不十分な場合や、より柔軟な条件で検索したい場面に適していると考えます。
使い分けの基準を整理
両者を使い分けるために以下の表で整理します。
使用ケース | context |
find_by |
---|---|---|
ログインユーザー関連データの取得 | ✅ | ❌ |
特定のIDを基にした検索 | ❌ | ✅ |
リレーション経由でのデータ取得 | ✅ | ❌ |
条件付き検索やフィルタリング | ❌ | ✅ |
存在しない可能性がある場合 | ❌ | ✅ |
単純なレコード検索や条件付き検索には find_by
を、ログインユーザーの情報取得のようなリレーション経由のデータ取得には context
が適していると考えます。
筆者の具体的な考えと実務上のポイント
使い分けを決定する重要な要素は「リレーションの有無」と「追加の条件設定の有無」と考えています。
context
が適する場面
def profile
context[:current_user].profile # リレーションのみで完結
end
このようにシンプルにリレーションだけで取得できるデータであれば、context
を優先して使うべきです。
find_by
が適する場面
def published_post(post_id:)
Post.find_by(id: post_id, status: 'published') # 特定条件付き
end
複雑な条件やフィルタリングが必要な場合は、find_by
の方が柔軟に対応できます。
こうした使い分けを意識する理由は、パフォーマンス最適化の観点からです。できるだけ不要なデータベースクエリを避けるためにも context
を使って取得済みのデータを再利用することが望ましいと考えています。
一方で、権限の判定や複数条件による絞り込みなどリレーションだけでは表現しづらい場面では find_by
の持つ柔軟性が大きな武器になります。
小さな部分ですが、技術選定やコード設計においてはトレードオフを意識して状況に応じた最適な判断を心がけていきたいと考えています。
最終的なまとめと推奨方針
-
リレーションが明確な場合 →
context[:current_user]
を活用 -
複数の条件でフィルタリングする場合 →
find_by
を利用 -
他ユーザーのデータを取得する場合 →
find_by
を利用 -
レコードが存在しない可能性がある場合 → 安全に
find_by
を利用
Discussion