Zaten var olan kimliği otomatik atayan Rails


93

Şöyle yeni bir kayıt oluşturuyorum:

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

Veritabanımda şu anda kamyon için birkaç bin varlık var, ancak bazı kimlikleri kullanılabilir bırakacak şekilde kimlikleri birkaçına atadım. Yani olan şey, rayların id = 150 ile öğe oluşturması ve iyi çalışması. Ancak daha sonra bir öğe oluşturmaya ve ona id = 151 atamaya çalışır, ancak bu kimlik zaten mevcut olabilir, bu nedenle şu hatayı görüyorum:

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

Ve eylemi bir dahaki sefere çalıştırdığımda, 152 no'lu id'yi atayacaktır, bu değer önceden alınmamışsa iyi çalışacaktır. Bir kimliğin atamadan önce var olup olmadığını kontrol etmek için rayları nasıl edinebilirim?

Teşekkürler!

DÜZENLE

Kamyon kimliği, kopyalanan şeydir. Kullanıcı zaten var ve bu durumda sabittir. Aslında ilgilenmem gereken eski bir konu. Bir seçenek, rayların bu sefer her kimliği otomatik olarak atamasına izin vererek tabloyu yeniden oluşturmaktır. Bunun en iyi seçenek olabileceğini düşünmeye başladım çünkü birkaç başka sorunum var, ancak bunu yapmak için geçiş çok karmaşık olacak çünkü Truck diğer pek çok tabloda yabancı bir anahtar. Rayların, Kamyon altında zaten depolanan aynı verilerle, otomatik olarak atanan kimliklerle ve mevcut tüm ilişkileri koruyarak yeni bir tablo oluşturmasını sağlamanın basit bir yolu olabilir mi?


neden rayların kimliği otomatik olarak atamasına izin vermiyorsunuz? Bu, herhangi bir çoğaltma tehlikesini ortadan kaldırır - yoksa bu, eski kimlikleri saklamanız gereken eski bir veri sorunu mu? Yeni bir nesne oluştururken olağan iş olmadığı için iş durumunu biraz anlamak istiyorum.
MBHNYC

@MBHNYC D-Nice'in şirketi oluştururken bir user_id atadığını düşünüyorum, sizin düşündüğünüz gibi id değil (ve ben de bir an yaptım).
Anil

Ooo iyi Anıl yakala - tamamen haklısın. @ D-Nice, belki tuhaf bir şey olması durumunda bu tablo için gönderinizi gönderinize ekleyin? Karışıklığı ortadan kaldırmak için o
user_id'yi

Hayır, maalesef net değildi, Şirket kimliği neyin kopyalanmakta olduğudur. Kullanıcı zaten var ve bu durumda sabittir. Aslında ilgilenmem gereken eski bir konu. Gönderiyi daha fazla bilgi ile düzenleyecek
D-Nice

Tabloyu yeniden oluşturmanız gerekmez. Sırayı sıfırlamak için cevabıma bakın.
Dondi Michael Stroma

Yanıtlar:


88

Rails muhtemelen yerleşik PostgreSQL dizisini kullanıyor. Bir sekans fikri, sadece bir kez kullanılmasıdır.

En basit çözüm, aşağıdaki gibi bir sorgu ile şirket.id sütununuzun sırasını tablodaki en yüksek değere ayarlamaktır:

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

Sıra adınız "company_id_seq", tablo adı "şirket" ve sütun adı "id" tahmin ediyorum ... lütfen bunları doğru olanlarla değiştirin. Sekans adını ile alabilir SELECT pg_get_serial_sequence('tablename', 'columname');veya tablo tanımına ile bakabilirsiniz \d tablename.

Alternatif bir çözüm, kaydetmeden önce yeni satırlar için şirket kimliğini manuel olarak ayarlamak için şirket sınıfınızdaki save () yöntemini geçersiz kılmaktır.


Bunun ne yapacağını tahmin ediyorum, şu anda en yüksek değer olan + 1 ile otomatik atama başlangıcı olur mu?
D-Nice

Sanırım sorumun en iyi cevabı bu, ancak ilgisiz nedenlerden dolayı, OP düzenlememde
D-Nice

Bunun neden başladığını anlamıyorum? Bu benim başıma geldi ve bunun nasıl mümkün olduğunu anlamak istiyorum.
Hunt Burdick

2
@Websitescenes, PostgreSQL'de bir SERIAL sütunu varsa (bir seri sütun, varsayılan değerin bir sıradaki sonraki değer olduğu bir sütundur), ardından tabloyu o sütundaki sabit değerlerle doldurursa, sıra otomatik olarak güncellenmeyecektir. Örnek: 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

207

Bunu benim için sorunu çözen yaptım.

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

Reset_pk_sequence'ı buldum! bu başlıktan. http://www.ruby-forum.com/topic/64428


4
Teşekkürler, en iyi çözüm. Veritabanı transferinden sonra aynı problemi yaşadım.
Oleg Pasko

63
Veya tek astarlı eşdeğeri (raylar konsolunu kopyalama / yapıştırma amaçları için):ActiveRecord::Base.connection.tables.each { |t| ActiveRecord::Base.connection.reset_pk_sequence!(t) }
Raf

Bunun nasıl senkronize olamayacağına dair bir fikriniz var mı?
Tall Paul

26

@Apie cevabına göre .

Aşağıdakilerle bir görev yapabilir ve ihtiyacınız olduğunda çalıştırabilirsiniz:

rake database:correction_seq_id

Bunun gibi görevler oluşturursunuz:

rails g task database correction_seq_id

Ve oluşturulan dosyaya ( lib/tasks/database.rake) şunu koyun:

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

Bana bir veritabanı sorunu gibi geliyor, Rails sorunu değil. Veritabanınızın idsütununuzda uygun olmayan bir kimlik kaynağı olması mümkün mü ? Test etmek için doğrudan veritabanınıza bir çift ekleme yapmayı deneyin ve aynı davranışın var olup olmadığını görün.


3
Neden olumsuz oy? Bu, artış sıranızı diğer mevcut değerlerden daha düşük bir şeye ayarlarsanız ve bu nedenle, veri eklerken ara sıra çarpışmalara rastlarsanız gerçekleşen tam davranıştır. Poster zaten bu vakaya düşen mevcut verilerin olduğunu söyledi.
mynameiscoffey

Ben ekleyebilirim. Bu hatayı aldıktan sonra, dizideki bir sonraki kimlik henüz alınmamışsa, aynı eylemi tekrar çalıştırabilir ve çalışmasını sağlayabilirim.
D-Nice

Görünüşe göre bu benim durumumdu - sorunla karşılaştım ama eklediğim bir sonraki kayıt iyi çalıştı, bu yüzden tohumu doğru yere almış olmalı.
Ben Wheeler

4

Bu sorunu aşağıdaki komutu kullanarak çözdüm.

Bunu raylar konsolunuzda çalıştırın

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