2012-06-17 29 views
75

tôi tạo ra một kỷ lục mới như vậy:Rails tự động gán id đó đã tồn tại

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

cơ sở dữ liệu của tôi hiện đang có vài ngàn đơn vị cho xe tải, nhưng tôi phân công của id để một vài trong số họ, trong một cách để lại một số id có sẵn. Vì vậy, những gì đang xảy ra là đường ray tạo mục với id = 150 và nó hoạt động tốt. Nhưng sau đó nó cố gắng để tạo ra một mục và gán nó id = 151, nhưng id có thể đã tồn tại, vì vậy tôi thấy 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ỉ cần chỉ định id 152, sẽ hoạt động tốt nếu giá trị đó chưa được thực hiện. Làm thế nào tôi có thể nhận được đường ray để kiểm tra xem một ID đã tồn tại trước khi nó gán nó?

Cảm ơn!

EDIT

Id xe tải là những gì đang được nhân đôi. 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 giải quyết. 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 bởi vì tôi có một vài vấn đề khác, nhưng việc di chuyển để làm điều này sẽ rất phức tạp vì Xe tải là chìa khóa ngoại trong nhiều bảng khác. Sẽ có một cách đơn giản để có đường ray tạo ra một bảng mới với cùng một dữ liệu đã được lưu trữ trong Xe tải, với ID được gán tự động và duy trì tất cả các mối quan hệ hiện có?

+0

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

+0

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

+0

Ooo tốt bắt Anil - bạn hoàn toàn đúng. @ D-Nice, có lẽ thêm di chuyển của bạn cho bảng này để bài viết của bạn trong trường hợp có một cái gì đó kỳ lạ? Tempting để chỉnh sửa rằng user_id để loại bỏ sự nhầm lẫn .. – MBHNYC

Trả lời

75

Đường ray có thể đang sử dụng trình tự PostgreSQL tích hợp sẵn. Ý tưởng về một chuỗi là nó chỉ được sử dụng một lần.

Giải pháp đơn giản nhất là để thiết lập trình tự cho cột company.id của bạn với giá trị cao nhất trong bảng với một truy vấn như thế này:

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

Tôi đoán vào tên chuỗi của bạn "company_id_seq", bảng tên "công ty" và tên cột "id" ... vui lòng thay thế chúng bằng đúng tên. 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.

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.

+0

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

+0

Đó là chính xác, xin lỗi tôi đã không giải thích kỹ hơn. –

+0

Tôi nghĩ rằng đây là câu trả lời hay 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 sẽ phải tìm cách sử dụng chiến lược tôi đã mô tả trong bản chỉnh sửa OP –

3

Nghe tôi như một vấn đề về 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ó hạt giống nhận dạng không đúng trên cột id của bạn không? Để 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 đó có tồn tại hay không.

+3

Tại sao lại là downvote? Đâ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 truy cập các va chạm khi chèn dữ liệu. Các poster đã nói có dữ liệu hiện có rơi vào trường hợp này. – mynameiscoffey

+0

Tôi có thể chèn tiền phạt. Sau khi tôi nhận được lỗi này, tôi có thể thực sự chạy cùng một hành động một lần nữa và có nó hoạt động, nếu id tiếp theo trong chuỗi chưa được thực hiện. –

+0

có vẻ như đây là tình trạng của tôi - tôi đã gặp vấn đề nhưng bản ghi tiếp theo tôi đã làm việc tốt, vì vậy nó phải có hạt giống vào đúng nơi. –

181

Tôi đã thực hiện việc 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 giao cơ sở dữ liệu tôi đã có cùng một vấn đề. –

+54

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 của ray): 'ActiveRecord :: Base.connection.tables.each {| t | ActiveRecord :: Base.connection.reset_pk_sequence! (T)} ' – Raf

+4

nó phải được chấp nhận trả lời !! oneone –

24

Dựa trên @Apie answer.

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

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 tin đượ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 
+3

Giải pháp tốt nhất, cảm ơn bạn. – monteirobrena

Các vấn đề liên quan