代码之家  ›  专栏  ›  技术社区  ›  Daniel Vandersluis

Ruby线程安全类变量

  •  1
  • Daniel Vandersluis  · 技术社区  · 15 年前

    我有许多模型可以根据用户的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 是一个类变量,因此,来自一个人所选区域设置的字符串会“流血”到另一个具有不同区域设置的用户身上。有没有办法设置 @弦乐 变量,以便它只在当前请求的上下文中生存?

    我试着换了 @弦乐 具有 Thread.current["#{self.name}_strings"] (这样每个类都有一个不同的线程变量),但在这种情况下,变量被保留在多个请求上,并且在更改区域设置时不会重新加载字符串。

    1 回复  |  直到 15 年前
        1
  •  3
  •   Sarah Mei    15 年前

    我看到两种选择。第一种方法是使@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