Posterous theme by Cory Watilo

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