How to make a per-request variable globally available?

Chris Kampmeier
2007-02-08T04:29:53Z

I''m developing a single application that responds to requests from two
domains. Various parts of my code need to work differently depending on
the request''s domain.

The typical solution would be to do something like this:

class ApplicationController < ActionController::Base
  before_filter :initialize_site

  # makes @site available to all controllers and views
  def initialize_site
    @site = Site.find_by_domain(request.domain)
  end
end

class Site < ActiveRecord::Base
  def find_by_domain(domain)
    # ...
  end
end


The problem is that I''d really like to have access to @site in my
models
as well, because it would make my controllers much much more DRY.

In this (contrived) example, imagine two seperate store-fronts, both
selling widgets from the same manufacturer. But we want some widgets to
appear in one store, and some in the other.

class Widget < ActiveRecord::Base
  belongs_to :manufacturer
  belongs_to :site
end

class Site < ActiveRecord::Base
  has_many :widgets
end

class Manufacturer < ActiveRecord::Base
  # This is bad because Manufacturer.find(1).widgets contains
  # widgets from both sites
  has_many :widgets

  # I want to do the following instead, but I can''t because
  # @site is not available to models because it''s a controller
  # instance variable:
  has_many :widgets, :conditions => {:site_id => @site.id}
end



So I have to do things like this instead:

class ManufacturersController < ApplicationController
  def show
    @manufacturer = Manufacturer.find(params[:id])

    @widgets = @manufacturer.widgets.select do |widget|
      widget.site == @site
    end
  end
end

Having to do things like that in almost every action in my controllers
is driving me nuts. It''s horribly un-DRY. I want to take care of the
site filtering at the model level, so my controllers and views don''t
even know the difference.

So the question is, what''s the best-practice for making a variable
available to all models, views, and controllers? A (gasp!) global
variable? This variable needs to be set at the beginning of each
request.

Completely different approaches to solving this problem much appreciated
as well.

Thanks for reading!