Rails “validates_uniqueness_of” Phân biệt chữ hoa chữ thường


93

Đây là mô hình (tôi đang sử dụng SQLLite3):

class School < ActiveRecord::Base

  validates_uniqueness_of :name

end

Ví dụ: sau khi tôi thêm "Yale", tôi không thể thêm "Yale" nhưng có thể thêm "yale". Làm thế nào tôi có thể làm cho trường hợp xác thực không phân biệt?

CHỈNH SỬA: Đã tìm thấy - Xác thực Bản ghi Hoạt động

Câu trả lời:


232

validates_uniqueness_of :name, :case_sensitive => falsethực hiện thủ thuật, nhưng bạn cần lưu ý rằng điều validates_uniqueness_ofđó không đảm bảo tính duy nhất nếu bạn có nhiều máy chủ / quy trình máy chủ (ví dụ: chạy Phusion Passenger, nhiều Mongrels, v.v.) hoặc máy chủ đa luồng. Đó là bởi vì bạn có thể nhận được chuỗi sự kiện này (thứ tự là quan trọng):

  1. Quy trình A nhận được yêu cầu tạo người dùng mới với tên 'foo'
  2. Quy trình B làm điều tương tự
  3. Quy trình A xác nhận tính duy nhất của 'foo' bằng cách hỏi DB xem tên đó có tồn tại hay không và DB cho biết tên đó chưa tồn tại.
  4. Quy trình B làm điều tương tự và nhận được phản hồi tương tự
  5. Quy trình A gửi inserttuyên bố cho bản ghi mới và thành công
  6. Nếu bạn có ràng buộc cơ sở dữ liệu yêu cầu tính duy nhất cho trường đó, Quy trình B sẽ gửi insertcâu lệnh cho bản ghi mới và không thành công với một ngoại lệ máy chủ xấu xí quay lại từ bộ điều hợp SQL. Nếu bạn không có ràng buộc cơ sở dữ liệu, việc chèn sẽ thành công và bây giờ bạn có hai hàng với tên 'foo'.

Xem thêm "Đồng thời và tính toàn vẹn" trong validates_uniqueness_oftài liệu Rails.

Từ Ruby on Rails phiên bản thứ 3 :

... mặc dù tên của nó, validates_uniqueness_of không thực sự đảm bảo rằng các giá trị cột sẽ là duy nhất. Tất cả những gì nó có thể làm là xác minh rằng không có cột nào có cùng giá trị với giá trị trong bản ghi đang được xác thực tại thời điểm xác thực được thực hiện. Có thể tạo hai bản ghi cùng một lúc, mỗi bản ghi có cùng giá trị cho một cột phải là duy nhất và để cả hai bản ghi vượt qua xác thực. Cách đáng tin cậy nhất để thực thi tính duy nhất là sử dụng ràng buộc cấp cơ sở dữ liệu. "

Xem thêm kinh nghiệm của lập trình viên này với validates_uniqueness_of.

Một cách mà điều này thường xảy ra là tình cờ gửi hai lần từ một trang web khi tạo tài khoản mới. Đây là một vấn đề khó giải quyết vì những gì người dùng sẽ nhận lại là lỗi thứ hai (xấu xí) và nó sẽ khiến họ nghĩ rằng đăng ký của họ không thành công, trong khi thực tế nó đã thành công. Cách tốt nhất mà tôi đã tìm ra để ngăn chặn điều này là sử dụng javascript để cố gắng ngăn việc gửi hai lần.


4
Xin lưu ý - đây là bản vá mà tôi đã gửi cho Rails để cố gắng khắc phục sự cố này bằng cách tối ưu hóa các ràng buộc cấp db: rails.lighthoosystempp.com/projects/8994-ruby-on-rails/tickets/…
Jordan Brough

Ngoài ra, có vấn đề lâu năm "người dùng nhấp đúp vào nút gửi", nhưng đó là cách khắc phục nhiều hơn bằng cách sử dụng: disable_with
Ghoti

76

Trong rails 3, bạn có thể làm điều này trong mô hình của mình:

validates :name, :uniqueness => true

hoặc không có phân biệt chữ hoa chữ thường

validates :name, :uniqueness => {:case_sensitive => false}

Đây chính xác là những gì tôi muốn.
Jigar Bhatt

1
Tôi đã làm Rails hơn 10 năm. Tôi không thể tin rằng tôi chỉ đang tìm hiểu về tùy chọn này. Luôn có điều gì đó mới để học trong Rails ... bất kể cấp độ kỹ năng của một người.
danielricecodes

24

Có một tùy chọn mà bạn có thể chỉ định phân biệt chữ hoa chữ thường

  validates_uniqueness_of :name, :case_sensitive => false

1

Có một câu hỏi tương tự nhưng câu trả lời thú vị hơn: https://stackoverflow.com/a/6422771

Về cơ bản, việc sử dụng :case_sensitive => falsethực hiện một truy vấn cơ sở dữ liệu rất kém hiệu quả.

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.