Validasi Uniqueness Attribute antar Model dalam Rails

KS Putra
Binar Academy
Published in
2 min readDec 4, 2018

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.

--

--