Search code examples
ruby-on-railsruby-on-rails-3controllerscopedefault-scope

Access Controller Variable on default_scope


My app is based on the subdomain. Each manager has it's own subdomain that should show only his auctions. I have:

class Lot < ActiveRecord::Base
  belongs_to :auction
end

class Auction < ActiveRecord::Base
  has_many :lots
  belongs_to :manager
end

class manager < ActiveRecord::Base
  has_many :auctions
end

If the app was accessed using a subdomain, I have a before_filter that do the following:

def load_manager
  @loaded_manager = Manager.find_by_subdomain(request.subdomain)
end

and on my Lot's default_scope, i'd like to do the following:

  default_scope {  @loaded_manager.present? ? where(deleted: false).joins(:auction => :manager).where("auctions.manager_id = ?", @loaded_manager.id) :  where(deleted: false)  }  

So that way wherever I'm on the website I'll just show the lots that belongs to the manager's auctions.

The problem is that I can't access @loaded_manager on the model. What's the best way for doing this?

http://railscasts.com/episodes/388-multitenancy-with-scopes?view=comments solves this issue!


Solution

  • You may store current manager in Manager model in before filter:

    def load_manager
      Manager.set_current(request.subdomain)
    end
    
    class Manager < ActiveRecord::Base
      cattr_accessor :current
    
      def self.set_current(subdomain)
        self.current = self.find_by_subdomain(subdomain)
      end
    end
    
    class Lot < ActiveRecord::Base
      default_scope { Manager.current.present? ? where(deleted: false).joins(:auction => :manager).where("auctions.manager_id = ?", Manager.current.id) : where(deleted: false) }
    end
    

    Update

    As @Mik_Die noticed it is not thread safe, for thread safe solution a reader may look at railscasts - multitenancy-with-scopes (code here). There we just store current_id in Thread.