# How to make a per-request variable globally available?

**URL:** <https://www.ruby-forum.com/t/how-to-make-a-per-request-variable-globally-available/84857>\
**Category:** Rails\
**Created:** [February 8, 2007, 5:29am UTC](https://www.ruby-forum.com/t/how-to-make-a-per-request-variable-globally-available/84857 "2007-02-08T05:29:53Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![kampers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/54ee81/32.png) [@kampers](https://www.ruby-forum.com/u/kampers)\
**Post date:** [February 8, 2007, 5:29am UTC](https://www.ruby-forum.com/t/how-to-make-a-per-request-variable-globally-available/84857/1 "2007-02-08T05:29:53Z")

</div>

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!

---

<div class="post-metadata">

**Author:** ![kampers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/54ee81/32.png) [@kampers](https://www.ruby-forum.com/u/kampers)\
**Post date:** [February 8, 2007, 5:08pm UTC](https://www.ruby-forum.com/t/how-to-make-a-per-request-variable-globally-available/84857/2 "2007-02-08T17:08:35Z")

</div>

> # makes @site available to all controllers and views
> 
> def initialize\_site  
> @site = Site.find\_by\_domain(request.domain)  
> end  
> end

You can use Thread.current to pass data to your models. Something  
like this:

def initialize\_site  
@site = Site.find\_by\_domain(request.domain)  
Thread.current[:site] = @site  
end

Aaron

---

<div class="post-metadata">

**Author:** ![kampers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/54ee81/32.png) [@kampers](https://www.ruby-forum.com/u/kampers)\
**Post date:** [February 8, 2007, 6:50pm UTC](https://www.ruby-forum.com/t/how-to-make-a-per-request-variable-globally-available/84857/3 "2007-02-08T18:50:14Z")

</div>

I have been playing with the id of something similar and have come up  
with this.

make a folder domains then for each domain add public, config and any  
other files you need to be site specific.

then start 2 seperate fcgi proccesses

if you set it up properly you can run two domains off the same  
application; and can put SITE in the enviroments folder

---

<div class="post-metadata">

**Author:** ![kampers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/54ee81/32.png) [@kampers](https://www.ruby-forum.com/u/kampers)\
**Post date:** [February 8, 2007, 7:39pm UTC](https://www.ruby-forum.com/t/how-to-make-a-per-request-variable-globally-available/84857/4 "2007-02-08T19:39:58Z")

</div>

Aaron wrote:

> You can use Thread.current to pass data to your models. Something  
> like this:
> 
> def initialize\_site  
> @site = Site.find\_by\_domain(request.domain)  
> Thread.current[:site] = @site  
> end

Thank you, that’s exactly what I needed.

After I did that I extended ActiveRecord.Base::find to put my conditions  
in at the highest level:

class Site \< ActiveRecord::Base  
def Site.current  
Thread.current[:site]  
end  
end

class Widget \< ActiveRecord::Base  
class \<\< self  
# keep a pointer to the old find  
alias :find\_without\_site :find

```
# extend find to always return widgets for the current site
def find(*args)
  self.with_scope(:find => {:conditions => {:site_id => 

```

Site.current.id}}) do  
self.find\_without\_site(\*args)  
end  
end  
end  
end

And it’s amazing. All unnecessary references to the site are gone from  
my controllers, and even the other models. Thanks again!

---

<div class="post-metadata">

**Author:** ![kampers](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/54ee81/32.png) [@kampers](https://www.ruby-forum.com/u/kampers)\
**Post date:** [February 8, 2007, 7:52pm UTC](https://www.ruby-forum.com/t/how-to-make-a-per-request-variable-globally-available/84857/5 "2007-02-08T19:52:55Z")

</div>

> Thank you, that’s exactly what I needed.

Your welcome

> ```
> end
> end
> 
> ```
> 
> end  
> end
> 
> And it’s amazing. All unnecessary references to the site are gone from  
> my controllers, and even the other models. Thanks again!

Scoped finds are great, and overriding the default find will  
automatically scope your associations too. But be aware that the  
find\_by convenience methods (find\_by\_name, find\_by\_id, etc…) are NOT  
scoped.

Aaron
