2009-09-01 92 views
1

我有一些基於用戶的i18n語言環境加載字符串集合的模型。爲了簡化起見,每一個這樣做的模型包括以下模塊:Ruby線程安全類變量

module HasStrings 
    def self.included(klass) 
    klass.extend ClassMethods 
    end 

    module ClassMethods 
    def strings 
     @strings ||= reload_strings! 
    end 

    def reload_strings! 
     @strings = 
     begin 
      File.open(RAILS_ROOT/'config'/'locales'/self.name.pluralize.downcase/I18n.locale.to_s + ".yml") { |f| YAML.load(f) } 
     rescue Errno::ENOENT 
      # Load the English strings if the current language doesn't have a strings file 
      File.open(RAILS_ROOT/'config'/'locales'/self.name.pluralize.downcase/'en.yml') { |f| YAML.load(f) } 
     end 
    end 
    end 
end 

我遇到了一個問題,但是,因爲@strings是一個類變量,因此,從一個人的選擇的語言環境的字符串用另一個區域設置「滲入」另一個用戶。有沒有辦法設置@strings變量,使其僅存在於當前請求的上下文中?

我試着用替換爲Thread.current["#{self.name}_strings"](以便每個類有不同的線程變量),但是在這種情況下,變量保留在多個請求上,並且在語言環境發生更改時不重新加載字符串。

+0

這是發生在開發中,還是在生產中,或兩者兼而有之? – 2009-09-01 16:24:22

+0

生產。在開發過程中,類會重新加載每個請求,所以它不會成爲問題。 – 2009-09-01 17:51:26

回答

3

我看到兩個選項。首先是讓@strings成爲一個實例變量。

但是,您可能會在單個請求中多次加載它們,因此您可以將@strings變爲針對字符串集合的區域設置的哈希值。

module HasStrings 
    def self.included(klass) 
    klass.extend ClassMethods 
    end 

    module ClassMethods 
    def strings 
     @strings ||= {} 
     string_locale = File.exists?(locale_filename(I18n.locale.to_s)) ? I18n.locale.to_s : 'en' 
     @strings[string_locale] ||= File.open(locale_filename(string_locale)) { |f| YAML.load(f) } 
    end 

    def locale_filename(locale) 
     "#{RAILS_ROOT}/config/locales/#{self.name.pluralize.downcase}/#{locale}.yml" 
    end 
    end 
end 
+0

我想遠離實例變量,因爲它在邏輯上下文中沒有意義,並且還有重用。不過我喜歡哈希的想法 – 2009-09-01 18:04:14