Làm cách nào để tạo một cột duy nhất và lập chỉ mục nó trong di chuyển Ruby on Rails?


416

Tôi muốn tạo một cột uniquetrong tập lệnh di chuyển Ruby on Rails. Cách tốt nhất để làm điều đó là gì? Ngoài ra có cách nào để lập chỉ mục một cột trong bảng không?

Tôi muốn thực thi uniquecác cột trong cơ sở dữ liệu chứ không phải chỉ sử dụng :validate_uniqueness_of.

Câu trả lời:


686

Câu trả lời ngắn cho các phiên bản cũ của Rails (xem các câu trả lời khác cho Rails 4+):

add_index :table_name, :column_name, unique: true

Để lập chỉ mục nhiều cột với nhau, bạn chuyển một mảng các tên cột thay vì một tên cột đơn,

add_index :table_name, [:column_name_a, :column_name_b], unique: true

Nếu bạn nhận được "tên chỉ mục ... quá dài", bạn có thể thêm name: "whatever"vào phương thức add_index để làm cho tên ngắn hơn.

Để kiểm soát chi tiết, có một executephương thức "" thực thi SQL thẳng.

Đó là nó!

Nếu bạn đang làm điều này như một sự thay thế cho các xác nhận mô hình cũ thông thường, hãy kiểm tra xem nó hoạt động như thế nào. Báo cáo lỗi cho người dùng có thể sẽ không đẹp như vậy nếu không có xác nhận ở cấp độ mô hình. Bạn luôn có thể làm cả hai.


36
+1 để đề xuất tiếp tục sử dụng validates_uniquety_of. Việc xử lý lỗi sạch hơn nhiều bằng cách sử dụng phương pháp này với chi phí cho một truy vấn được lập chỉ mục duy nhất tôi sẽ đề nghị anh ta thực hiện cả hai
Steve Weet

1
Tôi đã thử rằng nó dường như không hoạt động! Tôi có thể chèn hai bản ghi với cột_name mà tôi xác định là duy nhất! Tôi đang sử dụng Rails 2.3.4 và MySql có ý tưởng nào không?
Tâm

Tôi đã sử dụng đề xuất thứ hai cho bạn bằng cách sử dụng exec: exec "ALTER TABLE users ADD UNIQUE (email)" và nó hoạt động! không chắc chắn tại sao người đầu tiên không quan tâm đến việc biết
Tam

1
Nếu bạn gặp indexed columns are not uniquelỗi khi cố gắng tạo một chỉ mục duy nhất, đó có thể là do dữ liệu trong bảng đã chứa các bản sao. Hãy thử xóa dữ liệu trùng lặp và chạy lại di chuyển.
Hartley Brody

5
Nếu bạn nhận được "tên chỉ mục ... quá dài", bạn có thể thêm , :name => "whatever"vào add_indexphương thức để làm cho tên ngắn hơn.
Rick Smith

129

rails tạo di chuyển add_index_to_table_name cột_name: uniq

hoặc là

rails tạo di chuyển add_column_name_to_table_name cột_name: string: uniq: index

tạo ra

class AddIndexToModerators < ActiveRecord::Migration
  def change
    add_column :moderators, :username, :string
    add_index :moderators, :username, unique: true
  end
end

Nếu bạn đang thêm một chỉ mục vào một cột hiện có, hãy xóa hoặc nhận xét add_columndòng hoặc đặt một kiểm tra

add_column :moderators, :username, :string unless column_exists? :moderators, :username

5
Tôi ủng hộ điều này bởi vì tôi muốn hình thức dòng lệnh. Nhưng thật ngớ ngẩn khi nó thêm cột ngay cả khi tôi chỉ định add_index...và không add_column....
Tyler Collier

1
Yeap, có thể trong phiên bản tiếp theo.
d.danailov

49

Vì điều này chưa được đề cập nhưng trả lời câu hỏi tôi có khi tôi tìm thấy trang này, bạn cũng có thể chỉ định rằng một chỉ mục phải là duy nhất khi thêm nó qua t.referenceshoặc t.belongs_to:

create_table :accounts do |t|
  t.references :user, index: { unique: true } # or t.belongs_to

  # other columns...
end

(ít nhất là Rails 4.2.7)


42

Nếu bạn đang tạo một bảng mới, bạn có thể sử dụng phím tắt nội tuyến:

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

14

Tôi đang sử dụng Rails 5 và các câu trả lời trên hoạt động rất tốt; Đây là một cách khác cũng hiệu quả với tôi (tên bảng là :peoplevà tên cột là :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

Bạn có thể muốn thêm tên cho khóa duy nhất vì nhiều lần tên unique_key mặc định theo đường ray có thể quá dài mà DB có thể gây ra lỗi.

Để thêm tên cho chỉ mục của bạn, chỉ cần sử dụng name:tùy chọn. Truy vấn di chuyển có thể trông giống như thế này -

add_index :table_name, [:column_name_a, :column_name_b, ... :column_name_n], unique: true, name: 'my_custom_index_name'

Thông tin thêm - http://apidock.com/rails/ActiveRecord/ConnectionAd Chap / SchemaStatements / add_index


1
add_index :table_name, :column_name, unique: true

Để lập chỉ mục nhiều cột với nhau, bạn chuyển một mảng các tên cột thay vì một tên cột đơn.


0

Nếu bạn đã bỏ lỡ để thêm duy nhất vào cột DB, chỉ cần thêm xác thực này trong mô hình để kiểm tra xem trường này có phải là duy nhất không:

class Person < ActiveRecord::Base
  validates_uniqueness_of :user_name
end

tham khảo ở đây Trên đây chỉ dành cho mục đích thử nghiệm, vui lòng thêm chỉ mục bằng cách thay đổi cột DB theo đề xuất của @Nate

vui lòng tham khảo điều này với chỉ mục để biết thêm thông tin


2
Tôi không khuyên bạn chỉ nên thêm xác nhận mà không có chỉ mục tương ứng. Tùy chọn tốt hơn là dọn sạch mọi bản sao hiện có và sau đó thêm chỉ mục. Nếu không, bạn có nguy cơ làm mất hiệu lực dữ liệu hiện tại (điều này sẽ khiến bất kỳ cập nhật nào cho các hàng đó không thành công) và bạn vẫn có thể kết thúc bằng các bản sao nếu bạn có bất kỳ mã nào bỏ qua xác thực Rails. (ví dụ: khi chạy update_all hoặc chèn SQL trực tiếp)
Nate
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.