Ruby on Rails ActiveRecord geçişinde çok uzun dizin adlarını nasıl işleyebilirim?


391

Dört ilişkili tabloların yabancı anahtarlardan oluşturulan benzersiz bir dizin eklemek çalışıyorum:

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

Veritabanının dizin adı için sınırlaması, taşıma işleminin başarısız olmasına neden olur. İşte hata mesajı:

Dizin adı 'index_studies_on_user_id_and_university_id_and_subject_name_id_and_subject_type_id' tablo 'etüdleri' çok uzun; sınır 64 karakterdir

Bunu nasıl halledebilirim? Farklı bir dizin adı belirleyebilir miyim?

Yanıtlar:


589

Aşağıdakiler için :nameseçenek sağlayın add_index, örneğin:

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

Kullanılıyorsa :indexseçeneği referencesbir de create_tablebloğu, bu aynı seçenekler karma alır add_indexdeğeri olarak:

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

2
APIdock'a göre, isim bir sembol değil, bir dize olmalıdır
Jaco Pretorius

7
Bunun için aşağı sözdizimi remove_index :studies, :name => 'my_index'ihtiyacı olan herkes içindir
Kirk

On Rails ile 4.2.6çalışır index: { name: :my_index }. Sadece nameişe yaramadı.
monteirobrena

174

Ayrıca, bir create_tableblok içindeki sütun tanımlarındaki (geçiş üreticisinden aldığınız gibi) dizin adını da değiştirebilirsiniz .

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

5
Bunun orijinal sorudan çok sütunlu dizin oluşturmadığını unutmayın; sadece uzun bir endeks adının bir kısaltmadan nasıl kısaltılacağını gösteriyorcreate_table
Craig Walker

6
Bu, bir indeks ile bir isim aralıklı tablo üzerinde bir polimorfik referans oluşturmaya çalışırken bana yardımcı oldu t.references :searchable, polymorphic:true, index: {:name => "index_searches_on_searchable"}, bu durumda dizin aslında çok sütunlu (aranabilir_kimliği ve aranabilir_türü) ve oluşturulan isme ad alanının eklenmesi çok uzun oldu .
mkrinblk

benim için güzel, kompakt bir çözüm. Teşekkür ederim!
Sergio Belevskij

3
Ayrıca olması gerekir foreign_key: trueve bu arada, bu harika bir çözümdür, çünkü raylar jeneratör model:referencesformatı ile oluşturulmuş bir taşıma dosyanız olduğunda kullanımı en kolay
Abram

39

PostgreSQL de, varsayılan sınırı 63 karakterdir . Dizin adları benzersiz olması gerektiğinden, küçük bir toplantı yapmak güzeldir. Kullanıyorum (daha karmaşık yapıları açıklamak için örneği değiştirdim):

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

Normal endeks şöyle olurdu:

:index_studies_on_professor_id_and_user_id

Mantık şöyle olacaktır:

  • index olur idx
  • Tekil tablo adı
  • Birleşen kelimeler yok
  • Hayır _id
  • Alfabetik sıra

Hangi genellikle işi yapar.


1
Paylaşım için teşekkürler. Sınırlama gerçeği için Postgres belgelerini bağlayabilirseniz iyi olur.
JJD

Dizin yine de bu tabloya ait olduğu için dizin adında tablo adına ihtiyacımız var mı? Sadece görmediğim bir yerde faydalı olup olmadığını merak ediyorum.
Joshua Pinter

Dizini istediğiniz gibi adlandırabilirsiniz, ancak dizin adındaki tablo adının dizin adını benzersiz tutmaya yardımcı olduğunu düşünüyorum (zorunludur), iyi kapsamlıdır ve bazı hata iletisi okunabilirliğini geliştirir.
ecoologic


6

Önceki cevaba benzer: Normalde add_index satırınızla 'name' tuşunu kullanmanız yeterlidir:

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

2

Korkarım bu çözümlerin hiçbiri benim için işe yaramadı. Belki de belongs_topolimorfik bir ilişki için create_table geçişimi kullandığım için.

Ben aşağıda kodumu ve polimorfik dernekler ile bağlantılı olarak 'Dizin adı çok uzun' ararken başka tökezlemek durumunda bana yardımcı çözüm için bir bağlantı ekleyeceğiz.

Aşağıdaki kod benim için çalışmadı:

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

Bu kod benim için çalıştı:

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

Bu bana yardımcı olan SO S&A: https://stackoverflow.com/a/30366460/3258059


1

Ben bu sorunu vardı, ama timestampsfonksiyonu ile. Updated_at öğesinde 63 karakter sınırını aşan bir dizin otomatik olarak oluşturuluyordu:

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

Dizin adı 'index_toooooooooo_loooooooooooooooooooooooooooooong_on_updated_at' tablodaki 'toooooooooo_loooooooooooooooooooooooooooooong' çok uzun; sınır 63 karakterdir

timestampsDizin adını belirtmek için kullanmaya çalıştım :

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

Ancak, dizin adını hem updated_atve created_atalanlarına uygulamaya çalışır :

'Toooooooooo_loooooooooooooooooooooooooooooong' tablosundaki 'too_long_updated_at' dizin adı zaten var

Sonunda vazgeçtim timestampsve zaman damgalarını uzun yoldan yarattım:

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

Bu işe yarıyor ama timestampsyöntemle mümkün olup olmadığını duymak isterim !


0

oluştur_tablo: siz_tablo_adı do | t | t.references: studant, dizin: {ad: 'name_for_studant_index'} t.references: öğretmen, dizin: {name: 'name_for_teacher_index'} bitiş


0

Ben jeneratörleri çok kullanan bir proje var ve bu otomatik olması gerekiyordu, bu yüzden index_namefonksiyonu geçersiz kılmak için raylar kaynağından kopyaladı . Bunu şuraya ekledim 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

Gibi dizinler oluşturur ix_assignments_on_case_id__project_idve hala çok uzunsa 63 karaktere kısaltır. Tablo adı çok uzunsa bu hala benzersiz olmayacaktır, ancak tablo adını sütun adlarından ayrı kısaltmak veya gerçekte benzersiz olup olmadığını kontrol etmek gibi komplikasyonlar ekleyebilirsiniz.

Not, bu bir Rails 5.2 projesinden; bunu yapmaya karar verirseniz, kaynağı sürümünüzden kopyalayın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.