Rails 5 Active Record - возможно ли сохранить таблицу в памяти?

Если у нас есть небольшая таблица, которая содержит относительно статические данные, возможно ли, чтобы Active Record загружал их при запуске приложения, и никогда не приходилось обращаться к базе данных для этих данных?

Обратите внимание, что в идеале я хотел бы, чтобы эти данные были доступными для других моделей, которые имеют к ним отношение.

Примером может служить список стран с префиксом номера телефона - этот список вряд ли изменится, и если он это сделает, он будет изменен администратором. Другие таблицы могут иметь отношения с этим (например, учитывая пользователя, у которого есть ссылка на страну, мы можем захотеть найти префикс телефонного номера страны).

Я видел подобный вопрос здесь, но ему 6 лет и он относится к Rails 2, тогда как я использую Rails 5 и, возможно, с тех пор что-то было введено.

Предпочтительными решениями будут:

  1. Встроенные функциональные возможности Rails / ActiveRecord для однократной загрузки таблицы при запуске и, если впоследствии загружаются другие записи, в которых есть связи с кэшированной таблицей, то автоматическая ссылка на кэшированные объекты (т. Е. Ручного кэширования MyModel.all где-то недостаточно, поскольку отношения будут по-прежнему загружаться путем запроса к базе данных).
  2. Поддерживаемая библиотека, которая делает вышеперечисленное.
  3. Если ни то, ни другое не доступно, я полагаю, что альтернативным методом было бы определить статический набор данных как перечисление / хэш в памяти или аналогичный, и сохранить хеш-ключ в записях, которые имеют отношение к этим данным, и определить методы для этих моделей, чтобы поиск с использованием объекта в хэше с использованием ключа, сохраненного в базе данных. Это кажется довольно ручным, хотя...

[РЕДАКТИРОВАТЬ] Еще одна вещь, которую следует рассмотреть с потенциальными решениями - ручное решение (3) также потребует, чтобы пользовательские контроллеры и маршруты для таких данных были доступны через API. В идеале было бы неплохо иметь решение, в котором такие данные могли бы предлагаться через RESTful API (только для чтения - только GET), если необходимо, с использованием стандартных механизмов рельсов, таких как Scaffolding, без слишком большого ручного вмешательства.

2 ответа

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

Запись данных в хэш / массив ruby ​​не так уж плоха.

И если вы хотите использовать каркас CRUD, почему бы просто не использовать стандартный генератор моделей / контроллеров Rails? Неужели так плохо хранить статические данные в базе данных?

Третий вариант - сохранить ваши данные в файле в каком-либо сериализованном формате, а затем, когда ваше приложение загрузится, прочитать это и создать объекты ActiveRecord. Позвольте мне показать пример:

data.yml

---
- a: "1"
  b: "1"
- a: "2"
  b: "2"

Это файл YAML, содержащий массив хэшей; Вы можете создать такой файл с помощью:

require 'yaml'
File.open("path.yml", "w") do |f|
  data = [
    { "a" => "1", "b" => 1 },
    { "a" => "2", "b" => 2 }
  ]
  f.write(YAML.dump(data))
end

Затем, чтобы загрузить данные, вы можете создать файл в config/initializers/ (здесь все будет загружено рельсами):

конфиг / Инициализаторы /static_data.rb

require 'yaml'

# define a constant that can be used by the rest of the app
StaticData = YAML.load(File.read("data.yml")).map do |object|
  MyObjectClass.new(object)
end

Чтобы избежать необходимости писать миграции базы данных для MyObjectClass (когда он на самом деле не хранится в БД) вы можете использовать attr_accessor определения для ваших атрибутов:

class MyObjectClass < ActiveRecord::Base
  # say these are your two columns
  attr_accessor :a, :b
end

просто убедитесь, что не запускаются такие вещи, как save, delete, или же update на этой модели (если вы не monkeypatch эти методы).

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

  1. загрузить данные из YAML в список объектов Ruby
  2. изменить список объектов Ruby
  3. сериализовать все в YAML и сохранить его.

Таким образом, вы можете видеть, что вы на самом деле не делаете здесь дополнительные обновления. Вы можете использовать JSON вместо YAML, и у вас возникнет та же проблема. Благодаря встроенной в Ruby системе хранения PStore вы сможете обновлять объекты в индивидуальном порядке, но использование SQL для производственного веб-приложения - гораздо лучшая идея, и, честно говоря, все станет проще.

Выходя за пределы этих параметров "сериализованных данных", серверы хранения ключей сохраняют данные в памяти. Вещи, как Memcached и Redis.

Но вернемся к моей более ранней точке, если у вас нет веских причин не использовать SQL, вы только усложняете ситуацию.

Похоже, FrozenRecord отлично подойдет для того, что вы ищете.

Интерфейс, похожий на Active Record, для доступа только для чтения к статическим файлам данных разумного размера.

Другие вопросы по тегам