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


391

Я намагаюся додати унікальний індекс, який створюється із зовнішніх ключів чотирьох пов’язаних таблиць:

add_index :studies,
  ["user_id", "university_id", "subject_name_id", "subject_type_id"],
  :unique => true

Обмеження бази даних на ім'я індексу призводить до збою міграції. Ось повідомлення про помилку:

Назва індексу "index_studies_on_user_id_and_university_id_and_subject_name_id_and_subject_type_id" у таблиці "дослідження" занадто довга; ліміт - 64 символи

Як я можу впоратися з цим? Чи можу я вказати інше ім'я індексу?

Відповіді:


589

Надайте :nameваріант add_index, наприклад:

add_index :studies,
  ["user_id", "university_id", "subject_name_id", "subject_type_id"], 
  :unique => true,
  :name => 'my_index'

Якщо використовується :indexпараметр увімкнено referencesв create_tableблоці, він має ті самі хеші параметрів, що add_indexі його значення:

t.references :long_name, index: { name: :my_index }

2
Згідно APIdock, ім'я повинно бути рядком, а не символом
Jaco Pretorius

7
Синтаксис вниз для цього є remove_index :studies, :name => 'my_index'для всіх, хто цього потребує
Кірк

On Rails 4.2.6працює з index: { name: :my_index }. Тільки nameне вийшло.
monteirobrena

174

Ви також можете змінити ім'я індексу у визначеннях стовпців всередині create_tableблоку (наприклад, отриманого від генератора міграції).

create_table :studies do |t|
  t.references :user, index: {:name => "index_my_shorter_name"}
end

5
Зверніть увагу, що це не створює індекс багато стовпців з початкового запитання; це просто демонструє, як скоротити довге ім’я з індексуcreate_table
Крейг Уокер

6
Це допомогло мені, коли я намагався створити поліморфну ​​посилання на таблицю, розміщену на імені з індексом, t.references :searchable, polymorphic:true, index: {:name => "index_searches_on_searchable"}у цьому випадку індекс насправді був багатоколонкою (searchchable_id та searchchable_type), а додавання простори імен до сформованого імені стало дуже довгим .
mkrinblk

приємне, компактне рішення для мене. Дякую!
Серхіо Белевський

3
Це також має бути foreign_key: true, до речі, це чудове рішення, оскільки його найпростіше використовувати, коли у вас є файл міграції, створений у model:referencesформаті генератора рейки
Abram

39

У PostgreSQL обмеження за замовчуванням - 63 символи . Оскільки імена індексу повинні бути унікальними, приємно мати невелику умовність. Я використовую (я підробив приклад, щоб пояснити більш складні конструкції):

def change
  add_index :studies, [:professor_id, :user_id], name: :idx_study_professor_user
end

Нормальний показник був би:

:index_studies_on_professor_id_and_user_id

Логіка була б такою:

  • index стає idx
  • Назва єдиної таблиці
  • Жодних приєднувальних слів
  • Ні _id
  • Алфавітний порядок

Що зазвичай виконує роботу.


1
Дякую, що поділились. Було б добре, якби ви могли зв'язати документацію Postgres для факту обмеження.
JJD

Чи потрібна нам назва таблиці у назві індексу, оскільки індекс належить до цієї таблиці? Цікаво, якщо це корисно десь я не бачив.
Джошуа Пінтер

Ви можете назвати індекс тим, що вам потрібно, але я думаю, що ім'я таблиці в імені індексу допомагає зберегти унікальне ім'я індексу (що є обов’язковим), добре простежує та покращує читати повідомлення про помилки.
екологічний


6

Подібно до попередньої відповіді: просто використовуйте клавішу 'ім’я' у звичайному рядку add_index:

def change
  add_index :studies, :user_id, name: 'my_index'
end

2

Боюся, що жодне з цих рішень не працювало на мене. Можливо, тому, що я використовував belongs_toміграцію create_table для поліморфної асоціації.

Я додаю свій код нижче та посилання на рішення, яке допомогло мені у випадку, якщо хтось інший натикається під час пошуку "Ім'я індексу занадто довго" у зв'язку з поліморфними асоціаціями.

Наступний код для мене НЕ працює:

def change
  create_table :item_references do |t|
    t.text :item_unique_id
    t.belongs_to :referenceable, polymorphic: true
    t.timestamps
  end
  add_index :item_references, [:referenceable_id, :referenceable_type], name: 'idx_item_refs'
end

Цей код DID працює для мене:

def change
  create_table :item_references do |t|
    t.text :item_unique_id
    t.belongs_to :referenceable, polymorphic: true, index: { name: 'idx_item_refs' }

    t.timestamps
  end
end

Це питання, які допомогли мені вирішити: https://stackoverflow.com/a/30366460/3258059


1

У мене було це питання, але з timestampsфункцією. Автогенерація індексу на updated_at перевищувала межу 63 символу:

def change
  create_table :toooooooooo_loooooooooooooooooooooooooooooong do |t|
    t.timestamps
  end
end

Назва індексу 'index_toooooooooo_loooooooooooooooooooooooooooooong_on_update_at' на таблиці 'toooooooooo_loooooooooooooooooooooooooooooong' занадто довга; ліміт - 63 символи

Я намагався використовувати timestampsдля вказівки назви індексу:

def change
  create_table :toooooooooo_loooooooooooooooooooooooooooooong do |t|
    t.timestamps index: { name: 'too_loooooooooooooooooooooooooooooong_updated_at' }
  end
end

Однак це намагається застосувати ім'я індексу як до полів, так updated_atі до created_at:

Назва індексу "too_long_update_at" у таблиці "toooooooooo_loooooooooooooooooooooooooooooooong" вже існує

Нарешті я здався timestampsі просто створив часові позначки довгим шляхом:

def change
  create_table :toooooooooo_loooooooooooooooooooooooooooooong do |t|
    t.datetime :updated_at, index: { name: 'too_long_on_updated_at' }
    t.datetime :created_at, index: { name: 'too_long_on_created_at' }
  end
end

Це працює, але я хотів би почути, чи можливо це за допомогою timestampsметоду!


0

create_table: you_table_name do | t | t.references: studant, index: {name: 'name_for_studant_index'} t.references: учитель, індекс: {name: 'name_for_teacher_index'} кінець


0

У мене є проект, який багато використовує генератори, і він потребував цього, щоб він був автоматичним, тому я скопіював index_nameфункцію з джерела рейки, щоб змінити її. Я додав це в config/initializers/generated_index_name.rb:

# make indexes shorter for postgres
require "active_record/connection_adapters/abstract/schema_statements"
module ActiveRecord
  module ConnectionAdapters # :nodoc:
    module SchemaStatements
      def index_name(table_name, options) #:nodoc:
        if Hash === options
          if options[:column]
            "ix_#{table_name}_on_#{Array(options[:column]) * '__'}".slice(0,63)
          elsif options[:name]
            options[:name]
          else
            raise ArgumentError, "You must specify the index name"
          end
        else
          index_name(table_name, index_name_options(options))
        end
      end
    end
  end
end

Він створює подібні індекси ix_assignments_on_case_id__project_idі просто скорочує його до 63 символів, якщо він ще занадто довгий. Це все ще буде не унікальним, якщо назва таблиці дуже довге, але ви можете додати ускладнень, таких як скорочення назви таблиці окремо від назв стовпців або фактична перевірка на унікальність.

Зауважте, це проект Rails 5.2; якщо ви вирішили це зробити, скопіюйте джерело зі своєї версії.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.