Loading a fixture clobbers a global variable

I’m making use of a global variable to do dynamic scoping in my models.
For example, here is how one model is defined:

class Invitation < ActiveRecord::Base
belongs_to :site

Scope all find calls to the current site_id.

scoped_methods << {
:find => { :conditions => [ ‘site_id = ?’,
$site_id ] }
}
end

In my ApplicationController, $site_id is set in a before_filter which
determines which subdomain the request came from. With this, I can
perform finds on my models without having to pass in the site_id every
time. This works well, although I understand it violates the MVC
philosophy - please bear with me.

It works well, except for tests. Actually, it works in tests if I
manually set $site_id, but only if I am not loading a fixture for
this model. For example, the following actually works (note that my
fixtures are commented out):

require File.dirname(FILE) + ‘/…/test_helper’

class InvitationTest < Test::Unit::TestCase
#fixtures :invitations

def test_global_wierdness
$site_id = 1

i = Invitation.find_by_last_name("Jones")
assert_valid i

end
end

So, if I run this test and watch my test.log file, I can verify that the
SQL query is run with site_id=1. All is good.

However, if I uncomment the fixtures line and watch my test.log file, I
find that $site_id is no longer visible within the model and my SQL
query ends up searching for site_id=NULL.

What exactly is going on here? Does loading a fixture somehow clobber
global variables? I’ve tried renaming the global $site_id to something
different (since that’s also a field in my Invitations table) but that
makes no difference.

Also, I can load fixtures for other models and the global variable
still works. It’s only when I load a fixture for the Invitation model
that it disappears.

I’ve been struggling with this problem for many hours and would be
greatly indebted to anyone who could educate me.

Thanks,

Scott

On 1 Oct 2007, at 22:49, Scott Garman wrote:

What exactly is going on here? Does loading a fixture somehow clobber
global variables? I’ve tried renaming the global $site_id to something
different (since that’s also a field in my Invitations table) but that
makes no difference.

Rails overrides the setup method, and this is where the fixtures are
loaded (ie before the code in test_global_weirdness runs). This
causes invitation.rb to be loaded. At this point $site_id is not set
and so when scoped_methods << {:find => { :conditions => [ ‘site_id
= ?’,$site_id ] } } is evaluated, $site_id is nil.
If you don’t have invitations as a fixture, then invitation.rb is
only loaded when Invitation is used, i.e. after you’ve set $site_id.
So it’s not that fixtures are clobbering anything. You’ll also have
problems if different tests try to set $site_id to different values.
Fundamentally this approach seems unwise. If you absolutely had to,
you could set $site_id in test_helper.rb

Fred

Frederick C. wrote:

Rails overrides the setup method, and this is where the fixtures are
loaded (ie before the code in test_global_weirdness runs). This
causes invitation.rb to be loaded. At this point $site_id is not set
and so when scoped_methods << {:find => { :conditions => [ ‘site_id
= ?’,$site_id ] } } is evaluated, $site_id is nil.

Fred, I can’t thank you enough for such a clear explanation. I’m
evaluating other ways of scoping my models, but you’ve resolved this
particular mystery.

Thanks,

Scott