2013-03-09 2 views
1

전자해도 솔루션을 개발하고 있습니다.이 솔루션은 단일 레일 애플리케이션에 몇 가지 상점을 제공합니다.요청간에 루비 클래스 접근자를 재설정하는 방법은 무엇입니까?

여기 상점 관련 설정을 담는 수업이 있습니다.

# models/shop.rb 
class Shop < Settingslogic 
    source "#{Rails.root}/config/shop.yml" 

    def self.init!(shop) 
    namespace shop.to_s 
    load! 
    end 

end 

Shop :: init! config 파일 여기

에서 지정한 구간을로드하는 경우에 대비 YML 파일 : 나는 응용 프로그램 컨트롤러의 도메인 이름으로 가게를 요청 일치하는

# config/shop.yml 
shop_1: 
    shop_name: Shop 1 
shop_2: 
    shop_name: Shop 2 

.

# controllers/application_controller.rb 
class ApplicationController < ActionController::Base 
    before_filter :set_shop 

    protected 

    def set_shop 
    Shop.init! if request.domain.match(/^.*shop1\.com$/) 
     :shop_1 
    elsif request.domain.match(/^.*shop2\.com$/) 
     :shop_2 
    end 
    end 
end 

문제는 Shop이 요청 사이에 요청한 첫 번째 상점에 대한 설정을 어떻게 든 유지한다는 것입니다. 예를 들어 :

shop1.com

Shop.shop_name # => Shop 1 

shop2.com

Shop.shop_name # => Shop 1 

내가 application_controller.rb 또는 shop.rb. 하나에 약간의 변경을 할 때까지 초기 설정을 유지 (나는 그것이 대답의 첫 번째 열쇠라고 생각한다.)

내가 알고있는 것은 Settingslogic이 shop.yml의 각 옵션에 대한 attr_accessor를 정의한다는 것이다. 그들은 여전히 ​​다시로드 한 후 일을 내가 왜 그런 식으로 할 때, 그러나

(I 거짓 cache_classes와 개발 환경 = 작동)가 예상대로 작동

# models/shop.rb 
class Shop < Settingslogic 
    source "#{Rails.root}/config/shop.yml" 
    namespace "shop_#{Random.rand(1..2)}" 
    load! 
end 

를 - 그것은 매번 적절한 설정을로드합니다. 하지만이 단계에서는 도메인별로 상점 이름을 설정할 수 없습니다. 또한 외부에서 shop_name을 지정할 수 없으면 다른 상점을 테스트 할 수 없습니다. 그래서 나는 방법이 필요합니다.

나는

def self.init!(shop) 
    class_eval do 
    namespace shop.to_s 
    load! 
    end 
end 

class_eval을 시도했지만 도움이되지 않았다. 여기에 범위 지정에 대한 지식이 부족하다고 느낍니다. 잘못된 아이디어가 있습니까? 미리 감사드립니다.

+2

많은 상점이있는 경우 왜 여러 개의 'Shop' 인스턴스 대신 싱글 톤'Shop'을 사용하고 있습니까? –

+0

@AndrewMarshall 앱이 다른 상점이 있다는 것을 알지 못하기 때문에. Settingslogic의 하위 클래스 인 일반 Settings 모델처럼 상점 별 설정에 액세스하면됩니다. 유일한 차이점은'request.domain'에 따라 설정 파일의 다른 섹션을로드한다는 것입니다. –

+0

@AndrewMarshall 감사합니다. 문제가 무엇인지 깨달았을 때 귀하의 답변에 따라 요청 당 Shop의 새로운 인스턴스가 필요하다는 것을 알게되었습니다. –

답변

0

클래스 속성이 다음에 업데이트 될 때까지 보존되어서는 안되는 이유는 없습니다.

레일 앱의 개발 모드에서 코드가 변경되면 다시로드되기 때문에 클래스 변수를 재설정하는 부작용이 있지만 코드에 의존하고 싶지는 않습니다.

필터가 수행해야하는 작업은 현재 요청에 사용할 상점이 들어있는 @current_shop 인스턴스 변수를 설정하는 것입니다.

+0

예, 가게 이름 만 있으면 @current_shop은 괜찮습니다. 방금 구성 파일을 단순화했습니다. 컨트롤러 나 뷰 'Shop.tax' - - 모델 'Shop.email.general' - 우편물 을에 'Shop.layout' : 다른 응용 프로그램의 장소에서 액세스 할 수 있어야 다른 옵션이 있습니다 등 –

+0

두 번째 주석 클래스 캐싱에 대해 쓰고 있었고 전체적인 접근법이 잘못되어 있고 아마도 내 문제이기도합니다. 클래스에서 직접'load! '를 호출하는지, 아니면'init!'메소드에서 래핑하는지에 관계없이 프로덕션에서 기대했던대로 작동하지 않습니다. 대답 해줘서 고마워요. –

+0

어디서나 사용할 수있는 Shop.current 메소드를 사용하려면 스레드 로컬을 사용할 수 있습니다. –

0

나는 마침내 문제의 초기 계획을 고수하면서 "클래스 캐싱"문제가 발생하지 않는 방법에 대한 해결책을 찾았다.

이 항목의 내용은 my another question에 대한 답변을 기반으로합니다.

어쨌든 여기에 내가 shop.yml의 모든 섹션을로드하고 해당 섹션에 대한 호출을 전달 :: 현재있는 숍을 통해 액세스하기로 결정 새로운 Shop.rb

class Shop < Settingslogic 
    source "#{Rails.root}/config/shop.yml" 
    load! 

    def self.current=(shop) 
    Thread.current[:current_shop] = shop.to_sym 
    end 

    def self.current 
    self.send(Thread.current[:current_shop]) 
    end 
end 

입니다.

어디서나 Shop.current.nameShop.current.tax을 사용할 수 있으며 applicationController 또는 spec_helper에 설정된 상점에 해당합니다.

관련 문제