Ruby线程安全的类变量

时间:2009-09-01 14:55:43

标签: ruby-on-rails ruby static thread-safety

我有很多模型根据用户的i18n语言环境加载一组字符串。为了简化操作,每个模型都包含以下模块:

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变量,使其仅存在于当前请求的上下文中?

我尝试用@strings替换Thread.current["#{self.name}_strings"](这样每个类有一个不同的线程变量),但是在这种情况下,变量保留在多个请求上,并且当语言环境是时,字符串没有重新加载改变。

1 个答案:

答案 0 :(得分: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