Vladimir E
Vladimir E

Reputation: 47

Accessing object everywhere in rails app

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

Answers (1)

Frederick Cheung
Frederick Cheung

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

Related Questions