Rails tự động gán id đã tồn tại


92

Tôi tạo một bản ghi mới như vậy:

truck = Truck.create(:name=>name, :user_id=>2)

Cơ sở dữ liệu của tôi hiện có vài nghìn thực thể cho xe tải, nhưng tôi đã gán id cho một vài trong số chúng, theo cách để trống một số id. Vì vậy, những gì đang xảy ra là rails tạo mục với id = 150 và nó hoạt động tốt. Nhưng sau đó nó cố gắng tạo một mục và gán nó id = 151, nhưng id đó có thể đã tồn tại, vì vậy tôi gặp lỗi này:

ActiveRecord::RecordNotUnique (PG::Error: ERROR: duplicate key value violates unique constraint "companies_pkey" DETAIL: Key (id)=(151) already exists.

Và lần sau khi tôi chạy hành động, nó sẽ chỉ định id 152, sẽ hoạt động tốt nếu giá trị đó chưa được sử dụng. Làm cách nào tôi có thể lấy rails để kiểm tra xem một ID đã tồn tại hay chưa trước khi nó chỉ định nó?

Cảm ơn!

BIÊN TẬP

Id Xe tải là những gì đang được sao chép. Người dùng đã tồn tại và là một hằng số trong trường hợp này. Nó thực sự là một vấn đề di sản mà tôi phải đối phó. Một tùy chọn, là tạo lại bảng tại let rails tự động gán mọi id lần này. Tôi bắt đầu nghĩ rằng đây có thể là lựa chọn tốt nhất vì tôi còn gặp một số vấn đề khác, nhưng việc di chuyển để thực hiện điều này sẽ rất phức tạp vì Xe tải là một khóa ngoại trong rất nhiều bảng khác. Có cách nào đơn giản để rails tạo một bảng mới với cùng một dữ liệu đã được lưu trong Truck, với ID được gán tự động và duy trì tất cả các mối quan hệ hiện có không?


tại sao bạn không cho phép rails tự động gán ID? Điều đó sẽ loại bỏ mọi nguy cơ trùng lặp - hay đây là vấn đề dữ liệu kế thừa mà bạn phải giữ lại các ID cũ? Chỉ muốn hiểu trường hợp kinh doanh một chút vì đây không phải là trường hợp kinh doanh thông thường khi tạo một đối tượng mới.
MBHNYC

@MBHNYC Tôi nghĩ rằng D-Nice đang chỉ định user_id trong khi tạo công ty chứ không phải id như bạn đang nghĩ (và tôi cũng đã làm vậy trong giây lát).
Anil

Ooo bắt tốt Anil - bạn hoàn toàn đúng. @ D-Nice, có lẽ thêm sự di chuyển của bạn cho bảng này vào bài đăng của bạn phòng khi có điều gì đó kỳ lạ? Hấp dẫn để chỉnh sửa ra user_id rằng để loại bỏ sự nhầm lẫn ..
MBHNYC

Không, xin lỗi nó không rõ ràng, id Công ty là những gì đang được sao chép. Người dùng đã tồn tại và là một hằng số trong trường hợp này. Nó thực sự là một vấn đề di sản mà tôi phải đối phó. Will chỉnh sửa bài với biết thêm
D-Nice

Bạn không cần phải tạo lại bảng. Chỉ cần xem câu trả lời của tôi để thiết lập lại trình tự.
Dondi Michael Stroma

Câu trả lời:


87

Rails có thể đang sử dụng trình tự PostgreSQL được tích hợp sẵn. Ý tưởng của một trình tự là nó chỉ được sử dụng một lần.

Giải pháp đơn giản nhất là đặt chuỗi cho cột company.id của bạn thành giá trị cao nhất trong bảng với truy vấn như sau:

SELECT setval('company_id_seq', (SELECT max(id) FROM company));

Tôi đoán tên trình tự của bạn "company_id_seq", tên bảng "công ty" và tên cột "id" ... vui lòng thay thế chúng bằng những cái chính xác. Bạn có thể lấy tên chuỗi với SELECT pg_get_serial_sequence('tablename', 'columname');hoặc xem định nghĩa bảng với \d tablename.

Một giải pháp thay thế là ghi đè phương thức save () trong lớp công ty của bạn để đặt id công ty cho các hàng mới theo cách thủ công trước khi lưu.


Tôi đoán những gì sẽ làm là bắt đầu tự động gán với giá trị cao nhất hiện tại là + 1?
D-Nice

Tôi nghĩ rằng đây là câu trả lời tốt nhất cho câu hỏi của tôi, tuy nhiên, vì những lý do không liên quan, tôi đang sẽ phải tìm ra cách để sử dụng chiến lược i được mô tả trong OP chỉnh sửa của tôi
D-Nice

Tôi không hiểu tại sao điều này lại xảy ra bắt đầu? Điều này đã xảy ra với tôi và tôi muốn hiểu điều này có thể xảy ra như thế nào.
Hunt Burdick

2
@Websitescenes, nếu có cột SERIAL trong PostgreSQL (cột nối tiếp là cột trong đó giá trị mặc định là giá trị tiếp theo trong một chuỗi), thì hãy điền vào bảng các giá trị cứng trong cột đó, chuỗi sẽ không được cập nhật tự động. Ví dụ: create table t (id serial not null primary key); insert into t values (1); insert into t values (default); ERROR: duplicate key value violates unique constraint "t_pkey" DETAIL: Key (id)=(1) already exists.
Dondi Michael Stroma,

204

Tôi đã làm điều này để giải quyết vấn đề cho tôi.

ActiveRecord::Base.connection.tables.each do |t|
  ActiveRecord::Base.connection.reset_pk_sequence!(t)
end

Tôi đã tìm thấy reset_pk_sequence! từ chủ đề này. http://www.ruby-forum.com/topic/64428


4
Cảm ơn, giải pháp tốt nhất. Sau khi chuyển cơ sở dữ liệu, tôi gặp sự cố tương tự.
Oleg Pasko

61
Hoặc tương đương một lớp lót (cho mục đích sao chép / dán bảng điều khiển rails):ActiveRecord::Base.connection.tables.each { |t| ActiveRecord::Base.connection.reset_pk_sequence!(t) }
Raf

Bất kỳ ý tưởng làm thế nào điều này không đồng bộ?
Tall Paul

25

Dựa trên câu trả lời của @Apie .

Bạn có thể thực hiện một nhiệm vụ và chạy khi cần với:

rake database:correction_seq_id

Bạn tạo các nhiệm vụ như thế này:

rails g task database correction_seq_id

Và trong tệp được tạo ( lib/tasks/database.rake) đặt:

namespace :database do
    desc "Correction of sequences id"
    task correction_seq_id: :environment do
        ActiveRecord::Base.connection.tables.each do |t|
            ActiveRecord::Base.connection.reset_pk_sequence!(t)
        end
    end
end

4

Tôi nghe có vẻ giống như vấn đề cơ sở dữ liệu chứ không phải vấn đề Rails. Có thể cơ sở dữ liệu của bạn có một hạt giống danh tính không đúng trên idcột của bạn ? Để kiểm tra, hãy thử thực hiện một vài thao tác chèn trực tiếp vào cơ sở dữ liệu của bạn và xem liệu hành vi tương tự có tồn tại hay không.


3
Tại sao lại ủng hộ? Đây là hành vi chính xác xảy ra nếu bạn đặt chuỗi gia tăng của mình thành thứ gì đó thấp hơn các giá trị hiện có khác và do đó, đôi khi xảy ra xung đột khi chèn dữ liệu. Người đăng đã nói rằng có dữ liệu hiện có rơi vào trường hợp này.
mynameiscoffey

Tôi có thể chèn tốt. Sau khi gặp lỗi này, tôi thực sự có thể chạy lại cùng một hành động và để nó hoạt động, nếu id tiếp theo trong chuỗi chưa được thực hiện.
D-Nice

Có vẻ như đây là tình huống của tôi - tôi gặp sự cố nhưng bản ghi tiếp theo mà tôi chèn vào hoạt động tốt, vì vậy nó hẳn đã đưa hạt giống vào đúng vị trí.
Ben Wheeler

3

Tôi đã giải quyết vấn đề này bằng cách làm theo lệnh.

Chạy điều này trong bảng điều khiển rails của bạn

ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
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.