Rails 5 Active Record - возможно ли сохранить таблицу в памяти?
Если у нас есть небольшая таблица, которая содержит относительно статические данные, возможно ли, чтобы Active Record загружал их при запуске приложения, и никогда не приходилось обращаться к базе данных для этих данных?
Обратите внимание, что в идеале я хотел бы, чтобы эти данные были доступными для других моделей, которые имеют к ним отношение.
Примером может служить список стран с префиксом номера телефона - этот список вряд ли изменится, и если он это сделает, он будет изменен администратором. Другие таблицы могут иметь отношения с этим (например, учитывая пользователя, у которого есть ссылка на страну, мы можем захотеть найти префикс телефонного номера страны).
Я видел подобный вопрос здесь, но ему 6 лет и он относится к Rails 2, тогда как я использую Rails 5 и, возможно, с тех пор что-то было введено.
Предпочтительными решениями будут:
- Встроенные функциональные возможности Rails / ActiveRecord для однократной загрузки таблицы при запуске и, если впоследствии загружаются другие записи, в которых есть связи с кэшированной таблицей, то автоматическая ссылка на кэшированные объекты (т. Е. Ручного кэширования MyModel.all где-то недостаточно, поскольку отношения будут по-прежнему загружаться путем запроса к базе данных).
- Поддерживаемая библиотека, которая делает вышеперечисленное.
- Если ни то, ни другое не доступно, я полагаю, что альтернативным методом было бы определить статический набор данных как перечисление / хэш в памяти или аналогичный, и сохранить хеш-ключ в записях, которые имеют отношение к этим данным, и определить методы для этих моделей, чтобы поиск с использованием объекта в хэше с использованием ключа, сохраненного в базе данных. Это кажется довольно ручным, хотя...
[РЕДАКТИРОВАТЬ] Еще одна вещь, которую следует рассмотреть с потенциальными решениями - ручное решение (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 этапа:
- загрузить данные из YAML в список объектов Ruby
- изменить список объектов Ruby
- сериализовать все в YAML и сохранить его.
Таким образом, вы можете видеть, что вы на самом деле не делаете здесь дополнительные обновления. Вы можете использовать JSON вместо YAML, и у вас возникнет та же проблема. Благодаря встроенной в Ruby системе хранения PStore вы сможете обновлять объекты в индивидуальном порядке, но использование SQL для производственного веб-приложения - гораздо лучшая идея, и, честно говоря, все станет проще.
Выходя за пределы этих параметров "сериализованных данных", серверы хранения ключей сохраняют данные в памяти. Вещи, как Memcached и Redis.
Но вернемся к моей более ранней точке, если у вас нет веских причин не использовать SQL, вы только усложняете ситуацию.
Похоже, FrozenRecord отлично подойдет для того, что вы ищете.
Интерфейс, похожий на Active Record, для доступа только для чтения к статическим файлам данных разумного размера.