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 (usefind_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
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
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
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
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.
Top comments (0)