Access object throughout request lifecycle with CurrentAttributes
The use case I recently had was that a Cache-Control
header was being sent in
by the requester, and I needed the value of that header really quite deeply
into the application. I needed to store a variable throughout the
request-response life cycle.
There’s a Rails solution in CurrentAttributes.
# app/models/response_headers.rb
class ResponseHeaders < ActiveSupport::CurrentAttributes
attribute :cache_control
end
# app/controllers/home_controller.rb
class HomeController < ApplicationController
before_action :set_cache_headers
def index
end
private
def set_cache_headers
ResponseHeaders.cache_control = request.headers.fetch('Cache-Control', '')
end
end
# app/lib/something_else.rb
class SomethingElse
def cache_headers?
ResponseHeaders.cache_control.blank?
end
end
Threads
My initial implementation just used Thread.current[:response_headers]
directly and storing a singleton there.
As far as I know, CurrentAttributes is just sugar around that, and when you have a library already inside your codebase doing the thing you want to do, just lean on that to hide away complexity. CurrentAttributes leads to a fairly clean looking object and only a little documentation to understand what’s going on.
It has all the problems that come with threads though: if you spin up a thread to do some other piece of work, it won’t have access to the CurrentAttribute’d object. (Or it will, but it will be a new instance.)
It’s not all that typical to use threads (in my experience), so you may not think you’re using any but double check your other libraries. Many HTTP client libraries will use threads to parellelise requests.