简体   繁体   中英

Rails cross model validation

I have two tables one for members and the other for employees, both have an attribute called id_number this attribute is not required and can be null.

Is it possible to run a validation to ensure the uniqueness of the id_number , so that if an employee is added with the same id_number as an member or vice versa that it will give an error.

I am thinking of writing my own validation but hitting the db for each instance will be very slow as some companies upload 10's of thousands of employees at a time.

Yes that's possible with your own validation. I think you have to hit the database, otherwise you never could check if it exists already.

def your_validation
  employee_ids = Employee.all.map(&:id_number)
  member_ids = Member.all.map(&:id_number)
  id = self.id_number
  if employee_ids.include?(id) || member_ids.include?(id)
    errors.add(:id_number, "is already taken")
  end
end

I think adding an index to your id_number will be good.

UPDATE: The above method could be changed to following to improve the performance:

def your_validation
  employee_ids = Employee.all.map(&:id_number)
  if employee_ids.include?(self.id_number)
    errors.add(:id_number, "is already taken")
  else
    member_ids = Member.all.map(&:id_number)
    if member_ids.include?(self.id_number)
      errors.add(:id_number, "is already taken")
    end
  end
end

The first one is cleaner, the second one should be faster. But check this out with a lot of db entries and a benchmark tool.

I think you'll want something like this:

def your_validation
  if self.id_number.present?
    if Employee.exists?(:id_number=>self.id_number) || Member.exists(:id_number=>self.id_number)
      errors.add(:id_number, "is already taken")
    end
  end
end

if you have indices on the id_number columns this check should run very quickly and is the same check that validates_uniqueness_of would use within a single table. Solutions that involves fetching all ids into rails will start running into problems when the tables get large.

Another thing to note is that if your app runs multiple web server instances at a time these kinds of rails side checks can't 100% guarantee uniqueness as they are subject to races between threads. The only way to ensure uniqueness in such situations would be to use facilities built into your database or generate the id_numbers yourself from a source that precludes duplicates (such as a database sequence).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM