Birden çok sütunun benzersizliğini doğrulama


193

Gerçek bir kaydın yalnızca bir sütun değil, benzersiz olduğunu doğrulamanın bir raylı yolu var mı? Örneğin, bir arkadaşlık modeli / tablosu aşağıdaki gibi birden fazla özdeş kayda sahip olmamalıdır:

user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20

7
yoğun olursam beni affet ama bu durumda bu nasıl yardımcı olur?
re5et

2
modelinizde "validates_uniqueness_of" ifadesini kullanmayı deneyin. bu işe yaramazsa, add_index: table, [: column_a,: column_b],: unique => true) gibi bir deyim geçişi oluşturabileceğiniz bir dizin oluşturmaya çalışın
Harry Joy

1
@ HarryJoy, diye sordu Is there a rails-way way. Ve ona ray dışı bir yol sunuyorsun, ama standart. The Active Record way claims that intelligence belongs in your models, not in the database.
Yeşil

2
Ne yazık ki validates :field_name, unique: trueyarış koşullarına yatkındır, bu yüzden raylara karşı olsa da gerçek bir kısıtlama tercih edilir. @HarryJoy Kısıtlama yolunu açıklayan bir cevabı iptal edeceğim.
Pooyan Khosravi

1
daha iyi cevap o zaman aşağıda belirtilen tüm bu bir stackoverflow.com/a/34425284/1612469 her şeyin düzgün çalışmasını sağlamak için başka bir katman getiriyor gibi
Aleks

Yanıtlar:


319

Bir validates_uniqueness_ofçağrıyı aşağıdaki şekilde kapsayabilirsiniz .

validates_uniqueness_of :user_id, :scope => :friend_id

83
Sadece 2'den fazla alanda benzersizliği doğrulamanız gerektiğinde birden fazla kapsam parametresi geçirebileceğinizi eklemek istedim. Yani: scope => [: friend_id,: group_id]
Dave Rapin

27
Söyleyemeyeceğin garip validates_uniqueness_of [:user_id, :friend_id]. Belki bu yamanmalı?
Alexey

12
Alexey, validates_uniqueness_of [: user_id,: friend_id] sadece listelenen alanların her biri için doğrulama yapacak - ve bu belgelenmiş ve beklenen davranış
Nikita Hismatov 18:13

71
Rails 4'te bu şu şekilde olur: validates: user_id, uniqueness: {scope:: friend_id}
Marina Martin

3
Muhtemelen aşağıdaki gibi özel bir hata mesajı eklemek istersiniz: message => 'zaten bu arkadaş var.'
laffuste

137

Bir sütunda validatesdoğrulamak uniquenessiçin kullanabilirsiniz :

validates :user_id, uniqueness: {scope: :friend_id}

Birden çok sütundaki doğrulamanın sözdizimi benzerdir, ancak bunun yerine bir dizi alan sağlamalısınız:

validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}

Ancak , yukarıda gösterilen onaylama yaklaşımlarının bir yarış durumu vardır ve tutarlılığı sağlayamazlar. Aşağıdaki örneği düşünün:

  1. veritabanı tablosu kayıtlarının n alanla benzersiz olması beklenir ;

  2. her biri ayrı işlemler ( uygulama sunucuları, arka plan çalışan sunucuları veya ne kullanıyor olursanız olun ) tarafından işlenen birden çok ( iki veya daha fazla ) eşzamanlı istek, aynı kaydı tabloya eklemek için veritabanına erişim;

  3. aynı n alanı olan bir kayıt olup olmadığını her işlem paralel olarak doğrular ;

  4. her istek için doğrulama başarılı bir şekilde iletilir ve her işlem tabloda aynı verilerle bir kayıt oluşturur.

Bu tür davranışlardan kaçınmak için, bir db tablosuna benzersiz bir kısıtlama eklemeniz gerekir . add_indexAşağıdaki taşımayı çalıştırarak bir (veya birden çok) alan için yardımcı ile ayarlayabilirsiniz :

class AddUniqueConstraints < ActiveRecord::Migration
  def change
   add_index :table_name, [:field1, ... , :fieldn], unique: true
  end
end

Dikkat : Benzersiz bir kısıtlama ayarladıktan sonra bile, iki veya daha fazla eşzamanlı istek aynı verileri db'ye yazmaya çalışacaktır, ancak yinelenen kayıtlar oluşturmak yerine, bu ActiveRecord::RecordNotUniqueayrı ayrı ele almanız gereken bir istisna oluşturur:

begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end 

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.