Beberapa waktu yang lalu saya menemui situasi di mana saya harus melakukan validasi uniqueness di antara dua model. Saya memiliki dua model yang sama-sama memiliki atribut phone_number
dan dalam satu sistem yang saya bangun atribut ini harus unique.
Jika model A sudah memiliki phone_number
0811213305, maka model B juga tidak boleh memiliki phone_number
dengan nomor yang sama.
Ruby on Rails memberikan kemudahan untuk melakukan unique validation dalam satu model dengan cara yang sangat mudah, namun tidak untuk unique validation dalam dua atau lebih model. Berarti, saya harus membuat sendiri validasi ini.
Setelah melakukan riset, maka saya pun menemukan algoritma yang menurut saya cukup simpel dan mudah untuk direproduksi sesuai kebutuhan.
Berikut adalah code saya:
# app/models/concerns/validate_phone_number.rb
module ValidatePhoneNumber
extend ActiveSupport::Concern
@@included_classes = []
included do
@@included_classes << self
validate :phone_number_in_all_model
end
private
def phone_number_in_all_model
return if self.phone_number.blank?
@@included_classes.each do |klass|
scope = klass.where(phone_number: self.phone_number)
if self.persisted? && klass == self.class
scope = scope.where('id != ?', self.id)
end
if scope.any?
self.errors.add :phone_number, 'is already taken.'
break
end
end
end
end
Jangan lupa untuk include Module
di dalam masing-masing model yang hendak divalidasi.
# app/models/customer.rb
class Customer < ApplicationRecord
include ValidatePhoneNumber
end
# app/models/branch.rb
class Branch < ApplicationRecord
include ValidatePhoneNumber
end
Setelah memasukkan code ini, voila, maka atribut phone_number
akan dipaksa untuk unique di kedua model, yaitu model Customer dan model Branch.
Kelemahan dari code ini adalah masih memungkinkannya terjadi duplikasi atribut ketika race condition.
Semoga artikel ini bisa membantu yang sedang kesulitan.
Note:
- Code ini saya temukan di suatu artikel yang saya tidak bisa temukan lagi karena lupa kata kunci search google;
- Copas dari artikel saya
Top comments (2)
Tes
Tes lagi