Rails Sensitivitas Huruf "validates_uniqueness_of"

95

Berikut adalah modelnya (Saya menggunakan SQLLite3):

class School < ActiveRecord::Base

  validates_uniqueness_of :name

end

Misalnya, setelah saya menambahkan "Yale", saya tidak dapat menambahkan "Yale" tetapi dapat menambahkan "yale". Bagaimana cara membuat validasi tidak peka huruf besar / kecil?

EDIT: Ditemukan - Validasi Rekaman Aktif

GeekJock
sumber

Jawaban:

232

validates_uniqueness_of :name, :case_sensitive => falsemelakukan trik, tapi Anda harus diingat bahwa validates_uniqueness_oftidak tidak menjamin keunikan jika Anda memiliki beberapa server proses / server (misalnya berjalan Phusion Penumpang, beberapa mongrel, dll) atau server multi-ulir. Itu karena Anda mungkin mendapatkan urutan kejadian ini (urutannya penting):

  1. Proses A mendapat permintaan untuk membuat pengguna baru dengan nama 'foo'
  2. Proses B melakukan hal yang sama
  3. Proses A memvalidasi keunikan 'foo' dengan menanyakan DB apakah nama itu sudah ada dan DB mengatakan nama itu belum ada.
  4. Proses B melakukan hal yang sama dan mendapat respons yang sama
  5. Proses A mengirimkan insertpernyataan untuk rekor baru dan berhasil
  6. Jika Anda memiliki batasan database yang memerlukan keunikan untuk bidang itu, Proses B akan mengirimkan insertpernyataan untuk rekaman baru dan gagal dengan pengecualian server jelek yang kembali dari adaptor SQL. Jika Anda tidak memiliki batasan database, penyisipan akan berhasil dan Anda sekarang memiliki dua baris dengan 'foo' sebagai namanya.

Lihat juga "Konkurensi dan integritas" di validates_uniqueness_of dokumentasi Rails.

Dari Ruby on Rails Edisi ke-3 :

... terlepas dari namanya, validates_uniqueness_of tidak benar-benar menjamin bahwa nilai kolom akan unik. Yang bisa dilakukan hanyalah memverifikasi bahwa tidak ada kolom yang memiliki nilai yang sama dengan yang ada di rekaman yang divalidasi pada saat validasi dilakukan. Ada kemungkinan dua rekaman dibuat pada waktu yang sama, masing-masing dengan nilai yang sama untuk kolom yang harus unik, dan untuk kedua rekaman lolos validasi. Cara paling andal untuk menerapkan keunikan adalah dengan batasan tingkat database. "

Lihat juga pengalaman programmer ini dengan validates_uniqueness_of.

Salah satu cara yang biasa terjadi adalah pengiriman ganda yang tidak disengaja dari halaman web saat membuat akun baru. Ini sulit untuk dipecahkan karena apa yang akan diperoleh kembali oleh pengguna adalah kesalahan kedua (jelek) dan itu akan membuat mereka mengira pendaftaran mereka gagal, padahal pada kenyataannya itu berhasil. Cara terbaik yang saya temukan untuk mencegahnya adalah dengan menggunakan javascript untuk mencoba mencegah pengiriman ganda.

Jordan Brough
sumber
4
Sebagai catatan - berikut adalah tambalan yang saya kirimkan ke Rails untuk mencoba memperbaiki masalah ini dengan menggunakan batasan level db: rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/…
Jordan Brough
juga, ada masalah abadi "pengguna mengklik dua kali tombol kirim", tapi itu lebih merupakan perbaikan menggunakan: disable_with
Ghoti
78

Di rel 3 Anda dapat melakukan ini dalam model Anda:

validates :name, :uniqueness => true

atau tanpa case_sensitivity

validates :name, :uniqueness => {:case_sensitive => false}
MaximusDominus
sumber
Inilah yang saya inginkan.
Jigar Bhatt
1
Saya telah mengerjakan Rails selama lebih dari 10 tahun. Saya tidak percaya saya baru saja mempelajari tentang opsi ini. Selalu ada hal baru untuk dipelajari di Rails ... terlepas dari tingkat keahlian seseorang.
danielricecodes
25

Ada opsi di mana Anda dapat menentukan ketidakpekaan huruf besar / kecil

  validates_uniqueness_of :name, :case_sensitive => false
vrish88
sumber
1

Ada pertanyaan serupa tetapi jawabannya lebih menarik: https://stackoverflow.com/a/6422771

Pada dasarnya, menggunakan :case_sensitive => falsemelakukan kueri database yang sangat tidak efisien.

Victor S
sumber