Как я должен хранить значение для приложения Rails, которое периодически меняется, но должно быть доступно для всех пользователей?

#ruby-on-rails #global-variables

#ruby-on-rails #глобальные переменные

Вопрос:

У меня есть приложение только для API, встроенное в Rails, для которого требуется зашифрованный логин для получения токена. Впоследствии запросы на данные из API аутентифицируются с использованием значения токена в заголовке запроса.

У меня есть другое приложение Rails, которое использует этот API для нескольких разных целей. В настоящее время я настроил его на аутентификацию перед выполнением любого запроса, который получает токен для этого запроса.

Это нормально, за исключением того, что оно создает потенциальное условие гонки, как только приложение становится общедоступным. Возможно, что два запроса могут поступать практически одновременно, дважды сбрасывая токен, делая один из последующих запросов на данные us токеном, который больше не действителен.

Я хотел использовать глобальную переменную $ для хранения токена и даты / времени его обновления, чтобы он всегда был доступен для всех пользователей и обновлял токен, только если ему больше пары часов.

Это решило бы проблему состояния гонки, но из всего, что я читаю, ИСПОЛЬЗОВАНИЕ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ В RAILS ПЛОХО. Мне кажется, что этот вариант использования является исключением, но я хочу сделать это правильно.

Мой единственный вариант сохранить эти значения в моей собственной базе данных? Кажется глупым настраивать модель данных для таблицы, которая будет содержать только два столбца и две строки, но я не знаю, является ли это Rails Way (TM) или лучшим способом.

Приветствуются любые советы.

Комментарии:

1. Несколько пользователей используют один и тот же токен?

Ответ №1:

Для этого вы можете использовать кеш Rails. Оно сохраняется в памяти или в энергозависимой базе данных, такой как Redis. У вас может быть что-то вроде:

 def a_cool_token
  Rails.cache.fetch("a_cool_token", expires_in: 2.hours.to_i) do
    a_method_to_regenerate_a_cool_token
  end
end
 

Что произойдет, так это:

  1. При использовании a_cool_token для передачи его в запрос он попытается извлечь его из кэша;
  2. В случае, если срок действия этого ключа кэша истек или не определен, он возвращает a_method_to_regenerate_a_cool_token ;
  3. По истечении установленного времени expires_in ключ становится недействительным.

Вы всегда можете использовать более полный ключ кэша, используя для его создания некоторый запрос к базе данных, например:

 Rails.cache.fetch("a_cool_token/#{some_timestamp_that_gets_updated_with_a_cool_token}", expires_in: 2.hours.to_i)
 

Реализация def some_timestamp_that_gets_updated_with_a_cool_token может извлекаться при последнем обновлении токена, избегая устаревших ответов, если что-то еще изменяет токен снаружи a_cool_token

Я надеюсь, что это поможет указать вам на «хорошее» решение.

Комментарии:

1. Неплохо. Из любопытства, это to_i нужно 2.hours ?

2. expires_in должно быть целое число секунд 🙂

3. Итак, я делал, например, expires in 10.minutes (нет to_i ). И, похоже, это работает. Но это неверно?

4. Мне нравится это решение. Спасибо за помощь!

5. @jvillian это зависит от библиотеки, которая взаимодействует с базой данных, некоторые не поддерживают нецелые значения.