Làm cách nào để tôi xử lý các tên chỉ mục quá dài trong quá trình di chuyển Ruby on Rails ActiveRecord?


391

Tôi đang cố gắng thêm một chỉ mục duy nhất được tạo từ các khóa ngoại của bốn bảng được liên kết:

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

Giới hạn của cơ sở dữ liệu cho tên chỉ mục khiến việc di chuyển không thành công. Đây là thông báo lỗi:

Tên chỉ mục 'index_studies_on_user_id_and_university_id_and_subject_name_id_and_subject_type_id' trên bảng 'nghiên cứu' quá dài; giới hạn là 64 ký tự

Làm thế nào tôi có thể xử lý này? Tôi có thể chỉ định một tên chỉ mục khác nhau?

Câu trả lời:


589

Cung cấp :nametùy chọn add_index, ví dụ:

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

Nếu sử dụng :indextùy chọn trên referencestrong một create_tablekhối, nó sẽ lấy các tùy chọn băm tương tự add_indexnhư giá trị của nó:

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

2
Theo APIdock, tên phải là một chuỗi, không phải là biểu tượng
Jaco Pretorius

7
Cú pháp xuống cho điều này là remove_index :studies, :name => 'my_index'dành cho bất cứ ai cần nó
Kirk

Trên Rails 4.2.6hoạt động với index: { name: :my_index }. Chỉ namekhông làm việc.
monteirobrena

174

Bạn cũng có thể thay đổi tên chỉ mục trong các định nghĩa cột trong một create_tablekhối (chẳng hạn như bạn nhận được từ trình tạo di chuyển).

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

5
Lưu ý rằng điều này không tạo ra chỉ mục nhiều cột từ câu hỏi ban đầu; nó chỉ trình bày cách rút ngắn tên chỉ mục dài từ mộtcreate_table
Craig Walker

6
Điều này giúp tôi khi tôi đang cố gắng tạo một tham chiếu đa hình trên một bảng cách nhau tên với một chỉ mục t.references :searchable, polymorphic:true, index: {:name => "index_searches_on_searchable"}trong trường hợp này, chỉ mục trên thực tế là một cột nhiều (searchable_id và searchable_type) và việc thêm không gian tên trong tên được tạo đã trở nên rất dài .
mkrinblk

Giải pháp nhỏ gọn, đẹp cho tôi. Cảm ơn bạn!
Sergio Belevskij

3
Nhân tiện foreign_key: true, đây cũng là một giải pháp tuyệt vời vì nó dễ sử dụng nhất khi bạn có tệp di chuyển được tạo bằng model:referencesđịnh dạng trình tạo đường ray
Abram

39

Trong PostgreSQL, các mặc định giới hạn là 63 ký tự . Bởi vì tên chỉ mục phải là duy nhất, thật tuyệt khi có một quy ước nhỏ. Tôi sử dụng (tôi đã điều chỉnh ví dụ để giải thích các công trình phức tạp hơn):

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

Chỉ số bình thường sẽ là:

:index_studies_on_professor_id_and_user_id

Logic sẽ là:

  • index trở thành idx
  • Tên bảng số ít
  • Không có từ nối
  • Không _id
  • Thứ tự ABC

Mà thường làm công việc.


1
Cám ơn vì đã chia sẻ. Sẽ rất tuyệt nếu bạn có thể liên kết tài liệu Postgres cho thực tế giới hạn.
JJD

Chúng ta có cần tên bảng trong tên chỉ mục không vì chỉ mục thuộc về bảng đó? Chỉ tò mò nếu điều đó có lợi ở đâu đó tôi chưa từng thấy.
Joshua Pinter

Bạn có thể đặt tên cho chỉ mục những gì bạn muốn, nhưng tôi nghĩ rằng tên bảng trong tên chỉ mục giúp duy trì tên chỉ mục duy nhất (bắt buộc), có phạm vi tốt và cải thiện khả năng đọc thông báo lỗi.
thái học


6

Tương tự như câu trả lời trước: Chỉ cần sử dụng phím 'name' với dòng add_index thông thường của bạn:

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

2

Tôi sợ không có giải pháp nào trong số này làm việc cho tôi. Có lẽ bởi vì tôi đã sử dụng belongs_totrong quá trình di chuyển của mình cho một liên kết đa hình.

Tôi sẽ thêm mã của mình bên dưới và một liên kết đến giải pháp giúp tôi trong trường hợp có ai khác vấp ngã khi tìm kiếm 'Tên chỉ mục quá dài' liên quan đến các liên kết đa hình.

Các mã sau KHÔNG làm việc cho tôi:

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

Mã DID này hoạt động với tôi:

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

Đây là câu hỏi và trả lời SO giúp tôi hiểu: https://stackoverflow.com/a/30366460/3258059


1

Tôi đã có vấn đề này, nhưng với timestampschức năng. Nó đã tự động tạo một chỉ mục trên update_at vượt quá giới hạn 63 ký tự:

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

Tên chỉ mục 'index_toooooooooo_loooooooooooooooooooooooooooooong_on_updated_at' trên bàn 'toooooooooo_loooooooooooooooooooooooooooooong' quá dài; giới hạn là 63 ký tự

Tôi đã cố gắng sử dụng timestampsđể chỉ định tên chỉ mục:

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

Tuy nhiên, điều này cố gắng áp dụng tên chỉ mục cho cả hai trường updated_atcreated_at:

Tên chỉ mục 'too_long_updated_at' trên bàn 'toooooooooo_loooooooooooooooooooooooooooooong' đã tồn tại

Cuối cùng tôi đã từ bỏ timestampsvà chỉ tạo ra dấu thời gian trên con đường dài:

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

Cách này hiệu quả nhưng tôi rất muốn nghe nếu có thể với timestampsphương pháp này!


0

created_table: you_table_name do | t | t.references: studant, index: {name: 'name_for_studant_index'} t.references: teacher, index: {name: 'name_for_teacher_index'} end


0

Tôi có một dự án sử dụng máy phát điện rất nhiều và cần điều này là tự động, vì vậy tôi đã sao chép index_namechức năng từ nguồn đường ray để ghi đè lên nó. Tôi đã thêm cái này vào 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

Nó tạo ra các chỉ mục như ix_assignments_on_case_id__project_idvà chỉ cắt nó thành 63 ký tự nếu nó vẫn quá dài. Điều đó vẫn sẽ không phải là duy nhất nếu tên bảng rất dài, nhưng bạn có thể thêm các biến chứng như rút ngắn tên bảng riêng biệt với các tên cột hoặc thực sự kiểm tra tính duy nhất.

Lưu ý, đây là từ một dự án Rails 5.2; nếu bạn quyết định làm điều này, hãy sao chép nguồn từ phiên bản của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.