Come posso gestire nomi di indici troppo lunghi in una migrazione ActiveRecord di Ruby on Rails?


391

Sto cercando di aggiungere un indice univoco che viene creato dalle chiavi esterne di quattro tabelle associate:

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

La limitazione del database per il nome dell'indice causa il fallimento della migrazione. Ecco il messaggio di errore:

Il nome dell'indice "index_studies_on_user_id_and_university_id_and_subject_name_id_and_subject_type_id" nella tabella "studi" è troppo lungo; il limite è di 64 caratteri

Come posso gestirlo? Posso specificare un nome di indice diverso?

Risposte:


590

Fornire l' :nameopzione add_index, ad esempio:

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

Se si utilizza l' :indexopzione on referencesin un create_tableblocco, accetta le stesse opzioni hash del add_indexsuo valore:

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

2
Secondo APIdock il nome deve essere una stringa, non un simbolo
Jaco Pretorius,

7
La sintassi negativa per questo è remove_index :studies, :name => 'my_index'per chiunque ne abbia bisogno
Kirk,

On Rails 4.2.6funziona con index: { name: :my_index }. Solo namenon ha funzionato.
monteirobrena,

174

Puoi anche modificare il nome dell'indice nelle definizioni di colonna all'interno di un create_tableblocco (come nel caso del generatore di migrazione).

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

5
Si noti che ciò non crea l'indice multi-colonna dalla domanda originale; sta solo dimostrando come abbreviare un lungo nome indice da uncreate_table
Craig Walker il

6
Questo mi ha aiutato quando stavo cercando di creare un riferimento polimorfico su una tabella con spaziatura dei nomi con un indice, t.references :searchable, polymorphic:true, index: {:name => "index_searches_on_searchable"}in questo caso l'indice era in realtà un multi-colonna (searchable_id e searchable_type) e l'aggiunta dello spazio dei nomi nel nome generato è diventata molto lunga .
mkrinblk,

bella soluzione compatta per me. Grazie!
Sergio Belevskij,

3
Dovrebbe anche avere foreign_key: true, a proposito, questa è un'ottima soluzione poiché è la più semplice da usare quando si crea un file di migrazione con il model:referencesformato del generatore di rotaie
Abram,

39

In PostgreSQL, il limite predefinito è di 63 caratteri . Poiché i nomi degli indici devono essere univoci, è bello avere una piccola convenzione. Uso (ho ottimizzato l'esempio per spiegare costruzioni più complesse):

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

L'indice normale sarebbe stato:

:index_studies_on_professor_id_and_user_id

La logica sarebbe:

  • index diventa idx
  • Nome tabella singolare
  • Nessuna parola d'unione
  • No _id
  • Ordine alfabetico

Che di solito fa il lavoro.


1
Grazie per la condivisione. Sarebbe bello se potessi collegare la documentazione di Postgres per la limitazione.
JJD,

Abbiamo bisogno del nome della tabella nel nome dell'indice poiché l'indice appartiene comunque a quella tabella? Sono solo curioso di sapere se è utile da qualche parte che non ho visto.
Joshua Pinter,

Puoi nominare l'indice come vuoi, ma penso che il nome della tabella nel nome dell'indice aiuti a mantenere il nome dell'indice univoco (che è obbligatorio), ben definito e migliora la leggibilità dei messaggi di errore.
ecologico


6

Simile alla risposta precedente: basta usare il tasto 'name' con la normale riga add_index:

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

2

Temo che nessuna di queste soluzioni abbia funzionato per me. Forse perché stavo usando la belongs_tomia migrazione create_table per un'associazione polimorfica.

Aggiungerò il mio codice di seguito e un collegamento alla soluzione che mi ha aiutato nel caso in cui qualcun altro si imbattesse nella ricerca di "Nome indice troppo lungo" in relazione alle associazioni polimorfiche.

Il seguente codice NON ha funzionato per me:

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

Questo codice ha funzionato per me:

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

Queste sono le domande e risposte SO che mi hanno aiutato: https://stackoverflow.com/a/30366460/3258059


1

Ho avuto questo problema, ma con la timestampsfunzione. Stava generando automaticamente un indice su updated_at che ha superato il limite di 63 caratteri:

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

Il nome dell'indice "index_toooooooooo_loooooooooooooooooooooooooooooooong_on_updated_at" sul tavolo "toooooooooo_loooooooooooooooooooooooooooooooong" è troppo lungo; il limite è di 63 caratteri

Ho provato a usare timestampsper specificare il nome dell'indice:

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

Tuttavia, questo cerca di applicare il nome di indice ad entrambe le updated_ate created_atcampi:

Il nome indice 'too_long_updated_at' sul tavolo 'toooooooooo_loooooooooooooooooooooooooooooooong' esiste già

Alla fine ho rinunciato e ho timestampsappena creato i timestamp a lungo termine:

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

Funziona ma mi piacerebbe sapere se è possibile con il timestampsmetodo!


0

create_table: you_table_name do | t | t.references: studant, indice: {name: 'name_for_studant_index'} t.references: insegnante, indice: {name: 'name_for_teacher_index'} fine


0

Ho un progetto che usa molto i generatori e ne avevo bisogno per essere automatico, quindi ho copiato la index_namefunzione dall'origine delle rotaie per sovrascriverla. Ho aggiunto questo in 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

Crea indici come ix_assignments_on_case_id__project_id e li tronca a 63 caratteri se è ancora troppo lungo. Non sarà ancora univoco se il nome della tabella è molto lungo, ma puoi aggiungere complicazioni come abbreviare il nome della tabella separatamente dai nomi delle colonne o verificare effettivamente l'unicità.

Nota, questo proviene da un progetto Rails 5.2; se decidi di farlo, copia l'origine dalla tua versione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.