📊

【Rails × GraphQL 入門】contextとfind_byの使い分け具体例を用いて解説

2025/03/24に公開

contextfind_by の適切な使い分け

Rails アプリケーションで GraphQL を導入すると、データ取得に find_bycontext の2つの方法が使えます。どちらを使うかの判断はシンプルですが、適切な使い分けが開発の効率性を左右します。本記事では両者の特徴を掘り下げ、具体的なコード例を交えながらその判断基準を明確にします。

なお、ここでの内容は筆者の経験に基づく個人的な見解であり、環境やユースケースによって認識の齟齬や誤りがある場合があります。その点をご了承ください。


find_bycontext の違い

まず、それぞれの基本的な特徴を再確認しましょう。

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

ここでは iduser_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 の持つ柔軟性が大きな武器になります。

小さな部分ですが、技術選定やコード設計においてはトレードオフを意識して状況に応じた最適な判断を心がけていきたいと考えています。


最終的なまとめと推奨方針

  1. リレーションが明確な場合context[:current_user]を活用
  2. 複数の条件でフィルタリングする場合find_byを利用
  3. 他ユーザーのデータを取得する場合find_byを利用
  4. レコードが存在しない可能性がある場合 → 安全にfind_byを利用

参考記事

Discussion