Reputation: 47
I know this is 1001st question about global objects, but I think my situation is slightly different.
I'm working on ecommerce solution, which provides few different shops within a single rails application.
There is a class Shop which provides shop-specific logic and options. For example:
@shop.tax
should be accessible in models. Tax can differ depend on shop. eg 9%, 18%.
@shop.name
and @shop.layout
should be accessible in controllers and views.
@shop.email.general
for mailers.
I need to be able to create an instance of Shop in application controller and somehow pass it to the all application parts.
# controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :set_shop
protected
def set_shop
requested_shop = if request.domain.match(/^.*shop1\.com$/)
:shop_1
elsif request.domain.match(/^.*shop2\.com$/)
:shop_2
end
@shop = Shop.new(requested_shop)
end
end
I know that request-based logic should not be used in models, but I really need shop options there. In tests I could mock this "global" object like that Shop.new(:test_shop)
in spec_helper.
Is global variable my only choice? I've never used them.
I tried to use Settingslogic gem, but it defines attr_accessors for shop-specific options, and they persist between requests, which is not what I need.
Upvotes: 1
Views: 460
Reputation: 84114
One way of doing this would be something like
class Shop
def self.current=(shop)
Thread.current[:current_shop] = shop
end
def self.current
Thread.current[:current_shop]
end
end
Which allows you to maintain a separate current shop for each request.
The alternative is to pass the current shop around. It may seem tedious at first but can ultimately be simpler to reason about than global or pseudo global behaviour
Upvotes: 1