Краткий обзор привилегий UUID и краткое руководство о том, как использовать его в качестве первичного ключа в вашем приложении Rails.

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

Мотивация

Скрыть информацию в URL

Если мы используем увеличивающееся целое число в качестве идентификатора, мы предоставим информацию в URL-адресе, которая может быть выведена извне. Общее количество записей может быть одной из вещей, которые мы хотим сохранить в секрете.

Для этого нам потребуется внедрить и поддерживать дополнительные механизмы. С другой стороны, используя UUID, нам не нужно беспокоиться об этом, поскольку он обрабатывается из коробки.

# incrementing integer VS universally unique identifier
localhost:3000/articles/36
localhost:3000/articles/fc9b45f6–94eb-47b9-b029–3bc55f810a35

Дополнительный уровень безопасности

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

Однако я настоятельно рекомендую сначала реализовать авторизацию на основе разрешений. Простое владение конкретным UUID вовсе не должно означать предоставленный доступ.

Универсально уникальный в лучшем виде

Я знаю, это звучит пугающе, но с подходом UUID вы можете назначать идентификаторы объектов на стороне клиента или даже в других системах. Таким образом можно исключить накладные расходы на вызовы API. Это может быть полезно, в частности, в пакетных действиях.

При генерации стандартными методами UUID для практических целей уникальны.

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

Руководство по использованию

вступление

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

Это простой процесс с небольшими затратами на производительность. Настройка этого может быть совершенно другой игрой для других баз данных. Я уверен, что в Интернете есть множество ресурсов, где вы можете узнать больше. Это может быть сложный процесс, который не стоит награды. Удачи в любом случае!

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

Создать миграцию

Чтобы включить использование UUID в PostgreSQL, вам необходимо создать и запустить следующую миграцию.

# frozen_string_literal: true
class EnableUuid < ActiveRecord::Migration[6.0]
  def change
    enable_extension 'pgcrypto'
  end
end

Реализовать инициализатор

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

Чтобы избежать этой повторяющейся работы, мы создадим и запустим следующий инициализатор. Таким образом, при генерации миграций UUID по умолчанию будет использоваться в качестве первичного ключа.

config/initializers/generators.rb

# frozen_string_literal: true
Rails.application.config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid
end

Настройка модельных отношений

Единственное, что мы должны помнить, это то, что мы должны быть явными при определении отношений модели на уровне базы данных. Поскольку в качестве первичного ключа используется UUID, нам также нужно, чтобы наши внешние ключи были того же типа. Давайте посмотрим на следующий пример.

Представим, что мы хотим иметь модели Article и Author, и что они должны быть в отношении "один ко многим".

Для модели Article мы хотели бы, чтобы она принадлежала одному Author. Следовательно, нам понадобится ссылка, определенная в нашей миграции. Дополнительным шагом обычно является то, что нам нужно явно определить, что UUID является типом внешнего ключа.

Мы можем сделать это, добавив часть type: :uuid в определение ссылки. Миграция для создания таблицы articles должна выглядеть примерно так.

Как справиться с ловушками

Помимо многочисленных преимуществ, подход UUID в качестве первичного ключа имеет свои подводные камни, которые также рассматриваются сообществом. Один из них, который не подлежит обсуждению, заключается в том, что .first и .last ActiveRecord::Relation больше не будут работать должным образом.

Как мы уже знаем, эти методы используют столбец id для сортировки. Наличие значения UUID в этом столбце вместо обычного увеличивающегося целого числа приведет к неожиданному поведению.

Однако в Rails 6 появилась возможность переопределить столбец, используемый для неявного упорядочивания.

Мы можем использовать эту способность в нашей базовой абстрактной модели и использовать поле created_at. Следовательно, .first и .last снова будут правильно работать для всех моделей, которые унаследованы от них. Вот как это должно выглядеть.

# frozen_string_literal: true
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  self.implicit_order_column = 'created_at'
end

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

Заявление об ограничении ответственности

Использование UUID в качестве первичного ключа в новом проекте - это хорошая идея. Тебе решать.

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