Як зробити колонку унікальною та індексувати її в міграції Ruby on Rails?


416

Я хотів би зробити колонку uniqueв сценарії міграції Ruby on Rails. Який найкращий спосіб це зробити? Чи є спосіб індексувати стовпчик у таблиці?

Я хотів би застосувати uniqueстовпці в базі даних, а не просто використовувати :validate_uniqueness_of.

Відповіді:


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.

Це воно!

Якщо ви робите це як заміна для звичайних перевірок старої моделі, перевірте, як вона працює. Повідомлення про помилку користувачеві, ймовірно, не буде таким приємним без перевірок на рівні моделі. Ви завжди можете робити і те, і інше.


36
+1 за пропозицію продовжувати використовувати validates_uniqueness_of. Поводження з помилками набагато чистіше, використовуючи цей метод, для вартості одного індексованого запиту, я б запропонував, що він робить і те, і інше
Стів Веет,

1
Я спробував, що це, здається, не працює! Я міг би вставити два записи із ім'ям колонки, яку я визначив унікальною! Я використовую Rails 2.3.4 і MySql будь-які ідеї?
Там

Я використав вам другу пропозицію, використовуючи Execute: Execute "ALTER TABLE користувачів ADD UNIQUE (email)" і це працює! не знаю , чому перший не було б цікаво дізнатися
Tam

1
Якщо ви отримуєте indexed columns are not uniqueпомилку при спробі створення унікального індексу, це може бути тому, що дані в таблиці вже містять дублікати. Спробуйте видалити повторювані дані та запустіть міграцію знову.
Хартлі Броді

5
Якщо ви отримаєте "ім'я індексу ... занадто довге", ви можете додати , :name => "whatever"до add_indexметоду, щоб скоротити ім'я.
Рік Сміт

129

рейки генерують міграцію add_index_to_table_name column_name: uniq

або

рейки генерують міграцію add_column_name_to_table_name column_name: string: uniq: index

породжує

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

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

(як мінімум на Рейки 4.2.7)


42

Якщо ви створюєте нову таблицю, ви можете використовувати вбудований ярлик:

  def change
    create_table :posts do |t|
      t.string :title, null: false, index: { unique: true }
      t.timestamps
    end
  end

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

Можливо, ви хочете додати ім'я унікального ключа стільки разів, скільки за замовчуванням ім'я унікального ключа в рейках може бути занадто довгим, для чого БД може викинути помилку.

Щоб додати ім'я до свого індексу, просто скористайтеся 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

будь ласка, зверніться до цього з індексом для отримання додаткової інформації


2
Я б не рекомендував просто додавати перевірку без відповідного індексу. Кращий варіант - очистити всі наявні дублікати, а потім додати індекс. В іншому випадку ви ризикуєте визначити недійсними існуючі дані (що призведе до відмови будь-яких оновлень цих рядків), і ви все одно можете отримати дублікати, якщо у вас є код, який пропускає перевірку Rails. (наприклад, під час запуску update_all або прямих вставок SQL)
Нейт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.