Neil Middleton
Neil Middleton

Reputation: 22240

Why are my thread variables intermittent in Rails?

I have the following in my application controller:

before_filter :set_current_subdomain

  protected
    def set_current_subdomain
      Thread.current[:current_subdomain] = current_subdomain
      @account = Account.find_by_subdomain(current_subdomain)
    end

    def current_subdomain
      request.subdomain
    end

and then the following in some of my models:

default_scope :conditions => { :account_id => (Thread.current[:account].id unless Thread.current[:account].nil?) }  

Now, this works - some of the time. I for instance load up an index method and get back a list of records with the scope applied, but also sometimes get an empty list as Thread.current[:account_id] is coming out as nil, even though queries earlier in the request are working using the same value.

Question is, why is this not working, and is there a better way to set a variable that's global to the current request?

Upvotes: 1

Views: 1923

Answers (1)

tadman
tadman

Reputation: 211670

Manipulating the Thread local variables is a really bad idea and is going to lead to nothing but sadness, heartache, and pain. There's no guarantee that different parts of the request processing will be handled by the same thread, and because of this, your variables might end up getting lost.

The Rails convention is to create instance variables in the context of ApplicationController. In simple terms, all you really do is this:

class ApplicationController < ActionController::Base
  before_filter :set_current_subdomain

  attr_reader :current_subdomain
  helper_method :current_subdomain

protected
  def set_current_subdomain
    @current_subdomain = request.subdomain

    @account = Account.find_by_subdomain(@current_subdomain)
  end
end

Any @... type variables you create will be attached to the instance of the ApplicationController associated with the current request. It's important to note that each request will be issued a brand-new instance of the appropriate controller class.

You're free to create whatever instance variables you want provided they don't somehow conflict with those used by Rails itself but in general terms this doesn't happen very often and conflicts typically occur on method names instead.

Class-level instance variables will persist between requests in environments where the "cache classes" flag is enabled. In the development environment your controller class is re-loaded each time a request is made to ensure it reflects the current state of your source files.

Upvotes: 6

Related Questions