Как сделать столбец уникальным и проиндексировать его при переходе на Ruby on Rails?

416

Я хотел бы сделать колонку uniqueв сценарии миграции Ruby on Rails. Каков наилучший способ сделать это? Также есть способ индексировать столбец в таблице?

Я хотел бы применять uniqueстолбцы в базе данных, а не просто использовать :validate_uniqueness_of.

Tam
источник

Ответы:

686

Краткий ответ для старых версий Rails (см. Другие ответы для Rails 4+):

add_index :table_name, :column_name, unique: true

Чтобы индексировать несколько столбцов вместе, вы передаете массив имен столбцов вместо одного имени столбца,

add_index :table_name, [:column_name_a, :column_name_b], unique: true

Если вы получаете «имя индекса ... слишком длинное», вы можете добавить name: "whatever"метод add_index, чтобы сделать имя короче.

Для детального контроля есть executeметод " ", который выполняет прямой SQL.

Это оно!

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

NDP
источник
36
+1 за предложение продолжать использовать validates_uniqueness_of. Обработка ошибок намного чище, если использовать этот метод для расчета стоимости одного индексированного запроса. Я бы предположил, что он делает и то, и другое
Стив Уит,
1
Я пытался, что это не похоже на работу! Я мог бы вставить две записи с column_name, которые я определил как уникальные! Я использую Rails 2.3.4 и MySql какие-либо идеи?
Там
Я использовал второе предложение, используя execute: execute «ALTER TABLE users ADD UNIQUE (email)», и это работает! не уверен, почему первому не было бы интересно узнать
Там
1
Если indexed columns are not uniqueпри попытке создать уникальный индекс появляется ошибка, возможно, это связано с тем, что данные в таблице уже содержат дубликаты. Попробуйте удалить дубликаты данных и снова запустить миграцию.
Хартли Броуди
5
Если вы получаете «имя индекса ... слишком долго», вы можете добавить , :name => "whatever"к add_indexметоду , чтобы сделать имя короче.
Рик Смит
129

рельсы генерируют миграцию add_index_to_table_name имя_ столбца: uniq

или

рельсы генерируют миграцию add_column_name_to_table_name имя_ столбца: строка: uniq: индекс

генерирует

class AddIndexToModerators < ActiveRecord::Migration
  def change
    add_column :moderators, :username, :string
    add_index :moderators, :username, unique: true
  end
end

Если вы добавляете индекс в существующий столбец, удалите или прокомментируйте add_columnстроку или поставьте галочку

add_column :moderators, :username, :string unless column_exists? :moderators, :username
d.danailov
источник
5
Я проголосовал за это, потому что хотел форму командной строки. Но глупо, что он добавляет столбец, даже когда я указываю, add_index...и нет add_column....
Тайлер Коллиер
1
Да, возможно в следующей версии.
д.данаилов
49

Поскольку это еще не было упомянуто, но отвечает на вопрос, который у меня возник, когда я нашел эту страницу, вы также можете указать, что индекс должен быть уникальным при добавлении его через t.referencesили t.belongs_to:

create_table :accounts do |t|
  t.references :user, index: { unique: true } # or t.belongs_to

  # other columns...
end

(по крайней мере на Rails 4.2.7)

Стив Гросси
источник
42

Если вы создаете новую таблицу, вы можете использовать встроенный ярлык:

  def change
    create_table :posts do |t|
      t.string :title, null: false, index: { unique: true }
      t.timestamps
    end
  end
Pioz
источник
14

Я использую Rails 5, и приведенные выше ответы прекрасно работают; вот еще один способ, который также работал для меня (имя таблицы :peopleи имя столбца :email_address)

class AddIndexToEmailAddress < ActiveRecord::Migration[5.0]
  def change
    change_table :people do |t|
      t.index :email_address, unique: true
    end
  end
end
Николас Нельсон
источник
1

Возможно, вы захотите добавить имя для уникального ключа, так как много раз имя по умолчанию unique_key по rails может быть слишком длинным, для которого БД может выдать ошибку.

Чтобы добавить имя для вашего индекса, просто используйте name:опцию. Запрос на миграцию может выглядеть примерно так:

add_index :table_name, [:column_name_a, :column_name_b, ... :column_name_n], unique: true, name: 'my_custom_index_name'

Дополнительная информация - http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index

свопы
источник
1
add_index :table_name, :column_name, unique: true

Чтобы индексировать несколько столбцов вместе, вы передаете массив имен столбцов вместо одного имени столбца.

Мурали
источник
0

Если вы пропустили добавление уникальности в столбец БД, просто добавьте эту проверку в модель, чтобы проверить, является ли поле уникальным:

class Person < ActiveRecord::Base
  validates_uniqueness_of :user_name
end

см. здесь Выше только для целей тестирования, пожалуйста, добавьте индекс , изменив столбец БД, как предложено @Nate

пожалуйста, обратитесь к этому с индексом для получения дополнительной информации

Ravistm
источник
2
Я бы не рекомендовал просто добавлять валидацию без соответствующего индекса. Лучший вариант - очистить все существующие дубликаты, а затем добавить индекс. В противном случае вы рискуете сделать недействительными существующие данные (что приведет к сбою любых обновлений в этих строках), и вы все равно можете получить дубликаты, если у вас есть какой-либо код, пропускающий проверки Rails. (например, при запуске update_all или прямые вставки SQL)
Nate