DEV Community

Cover image for Rails Meets GraphQL: How to Master context and find_by with Examples
Takehiro_Yamazaki
Takehiro_Yamazaki

Posted on

1 1 1 1 1

Rails Meets GraphQL: How to Master context and find_by with Examples

Introduce

Ever wondered how to fetch data in Rails with GraphQL without overcomplicating things? You’ve got two trusty tools: context and find_by. Choosing the right one can make your code cleaner, your queries faster, and your app easier to maintain.

In this guide, I’ll break down their differences, walk you through real examples, and share some lessons learned from working with both in production.

⚠️ Note: This guide is based on my own experience. Depending on your project’s architecture, there might be some nuances or edge cases not covered here.


🔍 What’s the Deal with context and find_by?

Let’s start with the basics—what each one actually does.

🕵️‍♂️ find_by: The Database Detective

  • Searches the database based on given conditions.
  • Executes a fresh query every time—no caching.
  • Returns nil if no match (use find_by! to raise an error instead).
  • Doesn’t rely on model relationships—works anywhere.

🤝 context: The Request Sidekick

  • Stores temporary data shared across a GraphQL request.
  • Holds things like context[:current_user] for quick access.
  • Helps avoid redundant database calls by reusing already-fetched data.
  • Especially useful for accessing data tied to the logged-in user.

✅ When context Saves the Day

If you're fetching data tied directly to the authenticated user, context is your best friend.

Example: Fetching a User Profile

# File: 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: "Gets the current user's profile."

      def user_profile
        # Grabs the profile via the user’s relationship—no extra query needed
        context[:current_user].profile
      end
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Why it works:

Since context[:current_user] is already loaded, calling .profile just uses the ActiveRecord association—no additional database hit. This is perfect for performance-sensitive routes.


🔎 When find_by Takes the Lead

Sometimes you need more control—specific filters, IDs, or permissions. That’s where find_by comes in.

Example: Finding a Post by ID

# File: 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:)
        # Finds a post matching the ID and user, throws an error if not found
        Post.find_by!(id: id, user_id: context[:current_user].id)
      end
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Why use find_by!?

You're filtering not just by ID, but also by user_id—something relationships alone can't express. And with find_by!, you make sure an error is raised if the post doesn’t exist. (Use find_by if you’re okay with getting nil.)


🧠 Your Cheat Sheet for Choosing

Scenario context find_by
Fetching logged-in user data
Searching by a specific ID
Accessing data via relationships
Adding custom filters
Handling records that might be nil

Rule of thumb:

Use context for relationship-driven access. Use find_by when you need fine-grained filters or extra logic.


💭 My Two Cents from the Trenches

After using both in real-world Rails + GraphQL apps, here’s how I approach the decision:

🔄 Why I Reach for context

def profile
  context[:current_user].profile # Clean, quick, done
end
Enter fullscreen mode Exit fullscreen mode

If the data is tied to a user and you already have the user loaded, context gives you a fast, elegant solution. I’ve seen it reduce database queries significantly.

🔍 Why find_by Still Has Its Place

def published_post(post_id:)
  Post.find_by(id: post_id, status: 'published') # Filters like a champ
end
Enter fullscreen mode Exit fullscreen mode

Need filters? Want to find data that may or may not exist? Dealing with permissions? That’s find_by territory.


🚀 Wrapping Up: Your Action Plan

Here’s how to apply what you’ve learned:

  • Use context[:current_user] when working with logged-in user relationships.
  • Use find_by when:
    • You need to filter with custom conditions.
    • You're fetching another user’s data (with proper permission checks).
    • A record might not exist and you need graceful handling.

Mastering this distinction keeps your codebase clean, performant, and maintainable.


📚 Further Reading


Playwright CLI Flags Tutorial

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • 0:56 --last-failed
  • 2:34 --only-changed
  • 4:27 --repeat-each
  • 5:15 --forbid-only
  • 5:51 --ui --headed --workers 1

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Click on any timestamp above to jump directly to that section in the tutorial!

Watch Full Video 📹️

Top comments (0)

Playwright CLI Flags Tutorial

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • 0:56 --last-failed: Zero in on just the tests that failed in your previous run
  • 2:34 --only-changed: Test only the spec files you've modified in git
  • 4:27 --repeat-each: Run tests multiple times to catch flaky behavior before it reaches production
  • 5:15 --forbid-only: Prevent accidental test.only commits from breaking your CI pipeline
  • 5:51 --ui --headed --workers 1: Debug visually with browser windows and sequential test execution

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Click on any timestamp above to jump directly to that section in the tutorial!

Watch Full Video 📹️

👋 Kindness is contagious

DEV is better (more customized, reading settings like dark mode etc) when you're signed in!

Okay