Рубинобезопасные переменные класса - PullRequest
1 голос
/ 01 сентября 2009

У меня есть несколько моделей, которые загружают коллекцию строк в зависимости от локали 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 Ответ

3 голосов
/ 01 сентября 2009

вижу два варианта. Первое - сделать @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
...