Bạn có thể sử dụng validates
để xác nhận uniqueness
trên một cột:
validates :user_id, uniqueness: {scope: :friend_id}
Cú pháp xác thực trên nhiều cột là tương tự nhau, nhưng bạn nên cung cấp một mảng các trường thay thế:
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
Tuy nhiên , các phương pháp xác nhận được trình bày ở trên có một điều kiện cuộc đua và không thể đảm bảo tính nhất quán. Hãy xem xét ví dụ sau:
bản ghi bảng cơ sở dữ liệu được coi là duy nhất bởi n trường;
nhiều ( hai hoặc nhiều ) yêu cầu đồng thời, được xử lý bởi các quy trình riêng biệt ( máy chủ ứng dụng, máy chủ nhân viên nền hoặc bất cứ thứ gì bạn đang sử dụng ), truy cập cơ sở dữ liệu để chèn cùng một bản ghi vào bảng;
mỗi quá trình song song xác nhận nếu có một bản ghi với cùng n trường;
xác thực cho mỗi yêu cầu được thông qua thành công và mỗi quy trình tạo một bản ghi trong bảng có cùng dữ liệu.
Để tránh loại hành vi này, người ta nên thêm một ràng buộc duy nhất vào bảng db. Bạn có thể thiết lập nó với trình add_index
trợ giúp cho một (hoặc nhiều) trường bằng cách chạy di chuyển sau:
class AddUniqueConstraints < ActiveRecord::Migration
def change
add_index :table_name, [:field1, ... , :fieldn], unique: true
end
end
Hãy cẩn thận : ngay cả sau khi bạn đã đặt một ràng buộc duy nhất, hai hoặc nhiều yêu cầu đồng thời sẽ cố gắng ghi cùng một dữ liệu vào db, nhưng thay vì tạo các bản ghi trùng lặp, điều này sẽ đưa ra một ActiveRecord::RecordNotUnique
ngoại lệ, bạn nên xử lý riêng:
begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end