Как использовать тип поля json ActiveRecord

У меня есть модель Rails, которая имеет столбец базы данных типа "json":

create_table "games", force: true do |t|
  t.json     "game_board"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

Отлично! Теперь, как я могу его использовать? Действительно ли это так просто, как обрабатывать поле как Hash?

self.game_board[:player1] = 1
self.game_board[:cards] = cards.to_hash

Если бы я должен был написать это, все будет работать так, как ожидалось, поэтому в будущем вызове API от клиента я мог бы это сделать:

self.game_board[:player] # And get back the 1 that I put here before

Как насчет производительности? Будет ли все game_board десериализоваться каждый раз, даже если это поле никогда не читается? Будет ли переписываться поле (IOW database write) каждый раз, когда я меняю часть "Хеша?"

Ответ 1

Да, ActiveRecord позволяет использовать поля Postgres json просто как хэши в своих моделях. Однако есть несколько вещей, которые следует учитывать:

  • Хеш может быть NULL при инициализации
    В вашей миграции create_table вы разрешаете поле :game_board быть NULL. Таким образом, при первом использовании поле :game_board вашего экземпляра модели будет NULL, и вы должны сначала инициализировать Hash перед его использованием. (См. Пример ниже)

  • В JSON все клавиши являются строками
    Таким образом, при сохранении (и перезагрузке) все ключи будут преобразованы в строки, если раньше вы использовали Символы или Числа. Таким образом, для предотвращения нежелательного поведения рекомендуется использовать String-ключи, если ваш ORM не настроен для обозначения всех ключей.


Ваши примеры:

self.game_board         ||= {}
self.game_board[:player1] = 1
self.game_board[:cards]   = cards.to_hash

# after reload from database (access via String-key):
self.game_board['player1']  # And retrieve value 1 (that we put here before)


@Производительность:

  • Да, каждый раз, когда ActiveRecord считывает запись из базы данных и создает экземпляр модели, JSON-поля получают unserialized в хэши. Но если вы считаете, что это поражает ваше приложение, вы должны либо использовать текстовое поле, либо сериализовать/десериализовать JSON/хэши, когда вам нужно, или, что еще лучше, вообще не использовать ActiveRecord. Создавая кучи классов и используя магические методы, ActiveRecord создает так много накладных расходов, что вам не следует беспокоиться о десериализации JSON. У удобства есть свои затраты.

  • Да, каждый раз, когда вы изменяете значение в Hash, (целое) JSON-поле заменяется и обновляется новой сериализованной версией.
    Две заметки об этом:

    • Даже в Postgres (не только в ActiveRecord) возможность выполнения обновлений некоторых JSON-элементов отсутствует до сих пор. fooobar.com/info/550736/...
    • В общем, JSON-поля должны использоваться с фиксированной структурой или, по крайней мере, в управляемых размерах, а тип поля не должен быть хранилищем документов, например, например. в MongoDB. Сравните документацию Postgres