Rails has an decent set of validation rules for its database models. You can specify that particular variables must be present or satisfy certain constraints, either by themselves (“must be two characters long”) or in relation to each other (“password can’t be blank for administrators”). I’ve written several of my own extensions to these for validating phone numbers, email addresses, tracking numbers, and the like.
It works fine, at first. But model-based validation breaks down in several situations. Here are a few examples:
1. Wizard-like interfaces break the rules. By definition, a wizard decomposes the process into several steps. Your model objects are often invalid until you finish the last step. I have yet to see a solution to this. Most people end up adding some sort of knowledge about the wizard to the model’s validation code (“If I’m only asking for the person’s name and address right now, don’t try to validate his email address”).
2. In Rails, you can’t save your models unless they satisfy all of the validity conditions. This problem probably won’t arise at first, but as your code base evolves, it can have some nasty side-effects. Like when a user can’t change his password, because the model has lately been changed to require a variable that used to be optional.
Seaside itself provides nothing to help you with validation. Search some archives and you’ll find people recommending Magritte, which is a metadata descriptor system for model objects. It was written by Lukas Renggli, who is one of the lead developers of Seaside itself.
Magritte improves the problematic situations above in a couple of significant ways. For one, Magritte descriptions can be configured on any object, not just on database models. In Seaside, a wizard is likely to be implemented with several components (one per page), so a corresponding model could be built with just the validation rules it needs. Additionally, Magritte is completely separate from your persistence layer, so you are free to save your model objects regardless of whether Magritte’s validation rules are satisfied.
But I’m still not satisfied with the approach. Model-based validation has a bad smell to me, though in some limited ways I am sure it is useful. But the more I look at systems that work this way, the more I see what looks like UI-specific code in the model. Should your model really be concerned whether the user has entered matching strings for “password” and “password confirmation”? What if I want to use real first-class objects to represent a phone number? Validation should happen before the data ever gets to the model. It strikes me that validation belongs in the form, not in the model. In Seaside, that means that validation would happen at the component level.
So I’m looking for a better way. How are others handling validation in Seaside? Beyond that, how do other frameworks help with form validation? The most intriguing thing I’ve seen so far is the “newforms” framework in Django, which couples form inputs to their validation.
It seems that this would be fairly easy to implement in Seaside. You could use blocks to make its behavior pluggable. If you end up using one particular form in several places, make your own subclass of Form and reuse it. Or if you only need it once, build the Form instance programmatically.
Are there any other frameworks that provide validation hooks but are not model-based?