From: Tom Wardrop Date: 2011-01-01T10:09:59+09:00 Subject: Re: Where To Put Validation Logic? I appreciate the reply David. A little while after my initial post, I actually started coming to a similar conclusion as what you've described. The model should define the valid state of the system. This obviously does present a problem for a write-on-set database interface, because if you only set one field, even if you soon follow up by setting multiple other fields, the new or updated record will become invalid because it'll be missing field x, y and z. I did manage to come up with a solution however, which is something I had already planned to implement, but for a different purpose. I've decided to use a queuing construct. So if you've created a new object, or you need to update multiple fields, you can wrap such operations in a "set" block. For example... john.set do |doc| doc[:age] = 23 doc[:hair] = 'long' doc[:skin] = 'fair' end Or you could simply pass in a hash depending on the situation... john.set age: 23, hair: 'long', skin: 'fair' Single field write-on-set operation can still be performed using: john[:hair] = 'long', but if you wish to perform an operation that will invalidate the object for any period of time, you'll have to wrap the operations in a 'set' block. Behind the scenes, I've just implemented a simple queueing system which in essence, all it does is create a hash of new values which are only committed when commit() is called. Essentially, all the above set() method does, is the following internally... john.queue_updates = true john[:age] = 23 john[:hair] = 'long' john[:skin] = 'fair' # ...do plenty of other unrelated stuff here if you want... john.commit # Turn off queueing if you no longer wish to queue further operations. john.queue_updates = false I'm pretty happy with the solution I've managed to come up with here, as it's not just a construct for validation, but also allows one to batch operations to improve application performance. I'm yet to define the validation syntax, but it will be something like this... class Person define_valid do cond :name, :age, :email {|val| !val.empty? } cond :name {|val| val.gsub /.+ .+/ } cond :age {|val| val.is_a? Integer && (0..160) === val} cond :email {|val| val.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/)} end end As you can see, it uses blocks to define the validation logic. You can also map multiple fields to the same validation block. I still need to come up with an elegant way of setting validation messages. One idea is to simply return a string from the validation block when the condition fails, e.g. cond :name do |val| return "Name field must contain both a first and a last name." unless val.gsub /.+ .+/ end Whenever data is about to be committed, the validation conditions can be checked against the fields they apply to. This method allows one to define validations as complex or as simple as one desires. -- Posted via http://www.ruby-forum.com/.