A Complete Guide to Rails.current_attributes (ActiveSupport::CurrentAttributes)
Contents
Managing context like the current user, store, client, or request ID across controllers, models, jobs, and services in a Rails app has always been a little messy. Before Rails 5.2, you mightโve reached for Thread.current, class_attribute, or even @@class_variables to store this kind of state. But these are not thread-safe and can cause hard-to-debug issues in concurrent environments.
Rails 5.2 introduced a clean solution: ActiveSupport::CurrentAttributes.
This article covers what it is, why it exists, how it works internally, how to use it safely across web and background jobs, and how to test it properly.
๐ A Quick History
ActiveSupport::CurrentAttributes was introduced by DHH in Rails 5.2 to simplify access to per-request or per-job context in a thread-safe way. It replaced older, hackier methods like:
|
|
These approaches were shared across threads โ fine in development, dangerous in production.
CurrentAttributes changed that by giving you a dedicated, Rails-friendly API for storing context thatโs isolated per request/job.
๐งฉ What Is CurrentAttributes?
CurrentAttributes is a base class that lets you define request- or job-scoped attributes (like user, client, or store) and access them globally during execution.
|
|
Set it early in the request or job:
|
|
Now in any service, model, or job:
|
|
๐ซ Why Not Use class_attribute or Thread.current?
Because:
- โ
class_attributeand@@variablesare global across all threads. - โ
Thread.currentis unstructured and doesnโt reset automatically. - โ These approaches are hard to test and can lead to subtle concurrency bugs.
๐ How Does It Work Internally?
Storage
Each attribute is stored using Thread.current or Fiber.current (depending on your Ruby version), isolated per thread or fiber.
|
|
Resetting
Rails automatically resets context after each request using ActionDispatch::Executor:
|
|
You can (and should) call this manually at the end of background jobs.
โ Using It in Sidekiq
|
|
This is thread-safe: each Sidekiq job runs in its own thread, and CurrentAttributes isolates state per job.
โ Using It in Tests
Manual setup:
|
|
Shared helper:
|
|
Now in tests:
|
|
โ Best Practices
| Do โ | Donโt โ |
|---|---|
Set Current.* early |
Load values lazily from inside Current |
Use Current.set {} blocks |
Store heavy or unrelated state |
Reset Current after each job/test |
Use class_attribute for request context |
๐ง Summary
CurrentAttributesis a clean, thread-safe, per-request container.- Use it to store context like
user,store, andclient. - Set it early in controllers or jobs.
- Avoid putting logic inside it.
- Use
reset_allmanually in jobs and tests.
Itโs not just a substitute for class_attribute or Thread.current โ itโs the right tool for request-scoped state in modern Rails apps.