views:

364

answers:

1

I need to do conditional validation of models in Rails dependant on one of the fields within the model. This is a follow-up to an earlier question which prompted development of a solution that doesn't feel right.

I have a number of ActiveRecord models all based around an 'Order Model', a shortened version of which is shown below.

class Order < ActiveRecord::Base

  has_many: previous_addresses
  has_one: applicant
  has_one: current_address
end

All of the other models belong to order.

I wish to validate the various models such as applicant, current_address etc differently based upon the company attribute of the order.

I have developed a solution to this which involved a complete hand-rolled validation suite, supporting all of the standard activeRecord validators. This solution was developed with a number of tables such as model, fields, field_items etc that described the validation and amounts to quite a lot of data.

I now have to manipulate this data and copy and edit it for each new company that I am connecting to. This is tedious and error prone.

Whilst reading 'The Rails Way', I found a section where Obie Fernandez described keeping the validation code in the database in the form of ActiveRecord validation statements and injecting these into the models at runtime based upon the value of the company id.

I am imagining keeping data in tables such as the following :-

company: 200
model: person
Code validates_length_of :middle_name, :maximum => 20, :allow_nil => true

company: 201
model: person
Code validates_length_of :middle_name, :maximum => 1, :allow_nil => true

So for company 201 a middle name of 'John' would fail validation but that would be ok for company 200.

Has anyone seen this done, and if so do they have any tips/suggestions on how to do it, even better does anyone have any links to tutorials/ code that does this?

+1  A: 

It sounds like what you need is the ability to validate each record separately. If this is true then you could use validates_each. In this block you can pass in logic to evaluate the members of your model.

 validates_each :middle_name do |record, attr, value|
   if record.company == 201
     record.errors.add attr, 'cannot be more than 1 character' if value.length > 1
   elsif record.company == 200
     record.errors.add attr, 'must be less than 20 characters' if value.length > 1
   end
 end
vrish88
This would undoubtedly work but I'm trying to avoid the huge chain of ifs that this will cause as the number of companies grows. The idea is to add validation code to the database for each company rather than list them all in the model. This should make for easier maintenance
Steve Weet