Access request object from models and more
Sometimes for some weird reason you need to use cookie, session or even request objects from controller in models. In my case I needed unique token for each http request inside logic.
First thing got to my mind was to take request object from controller (ActiveDispatch::Request) and grab it’s object_id.
But then I realized that I need it in deep layers of application logic, and carrying it from controller would be quite painful.
I tried using a singleton class. It was good idea at first:
# lib/token.rb require 'singleton' class Token include Singleton attr_accessor :token_object def self.set(val) instance.token_object = val end def self.get instance.token_object.object_id.to_s end end # app/application_controller.rb class ApplicationController < ActionController::Base before_filter :setup_token def setup_token Token.set(self.request) end end
I was intended to use Token.get in app.
This way has a potential issue – race condition. If application would not be preforked, but executed in threads, the object could be modified from another thread. I wrote a little test case spawning few threads, setting some value and sleeping for a random time. Value was indeed changed by other threads.
Dmytro Shteflyuk helped me a lot pointing to solution based on thread variables. I found basic idea in Geoff Lane’s blog and came with a simple solution:
class Token def self.set(obj) Thread.current[:token] = obj end def self.get Thread.current[:token].nil? ? nil : Thread.current[:token].object_id end end