
Validation Dicussion
Reported by spgarbet | November 26th, 2007 @ 11:06 AM
I like what I see with data mapper. There has been an ongoing debate (2+ years) about validations in Rails. I wondered what the waters are like over here.
The essence of the debate centered around the orthogonality of the validation operators. When calling things like validates_format_of, and the column being nil, one gets a validates_presence_of automatically. Implying that validates_format_of and validates_presence_of are non-orthogonal. It would be better if these operators are orthogonal, and one only gets what is explicitly asked for and there is no automatic inclusion between validators. Short of that, at least make it configurable to allow for this. The rails core team has stubbornly refused to allow this to be configurable, only to have the issue raised up again repeatedly.
Hence, models end up with :allow_nil => true all over validations in a non-DRY manner.
I've also found validates_absence_of to be useful in STI situations where a field should not be defined for a subclass.
I'll write code/tests for these things if this is acceptable. Otherwise, I'll go quitely away.
Comments and changes to this ticket
-
Shalev NessAiver November 26th, 2007 @ 01:18 PM
I agree (about the orthogonality.) Why not make it the opposite and create an :allow_nil => false flag.
That way you don't need to create a whole other (validates_presence_of) if you don't want to.
-
Paul Sadauskas (Rando) November 26th, 2007 @ 05:14 PM
Since we are already defining the properties of a model, and using that to create the database columns, I would be with thinking about adding it to the #property class method.
It would be nice to be able to say:
class Person property :name, :string, :not_null => true end
And automatically get a validates_presence_of :name. Or the opposite, validates_presence_of would set the NOT NULL constraint on the column.
Some of the validators are to complex to encode in database constraints, but the simple ones (not null, unique, etc..) should be part of the table schema, as well as validators.
-
spgarbet November 28th, 2007 @ 11:08 AM
Paul,
I like the cut of your jib. That's exactly what's needed. All database constraints are reflected into validations automatically. Then one can add constraints as needed. Super!
-
Sam Smoot December 28th, 2007 @ 10:43 PM
- Milestone cleared.
- State changed from new to open
All good stuff. Right, don't want to stuff every validation into the property declaration, but basic ones for presence, size/allowed-range, format, etc seem like a great match.
Happy to consider any contributions on this front...
Not quite sure I agree with the original description of the ticket with regards to orthogonality... guess I could go either way on that.
I do think validations probably need to be accrued in a Set however, so you don't get lousy error messages, but that's more for the author of the Validatable gem. IOW, if you add a validates_length_of, along with a validates_presence_of on the same attribute, I imagine you could get a list of errors saying that:
- Age must not be blank
- Age must be between 18 and 65
Which could probably be better represented by not displaying the validates_presence_of message once a not-nullable range validation was added.
If that makes any sense.
Anyways, we should probably start with specs we can agree on before going off coding up an implementation, so if anyones game for that...
-
Sam Smoot January 2nd, 2008 @ 03:45 PM
- Assigned user set to Bernerd Schaefer
Bernerd's done some of this now I think...
-
Bernerd Schaefer January 3rd, 2008 @ 05:28 PM
I added #auto_validations! to DM::Property.
Now if you do:
class Zoo property :name, :string, :nullable => false, :default => "Zoo" end
It adds a validates_presence_of to :name.
I'm working on adding some of the other basic validations.
-
Bernerd Schaefer January 3rd, 2008 @ 06:28 PM
[r670]
Now you can do length/size validation and format (using the formats defined in validatable).
class Zoo include DataMapper::Persistence property :name, :string, :size => 250 # adds: validates_length_of :name, :maximum => 250 end class User include DataMapper::Persistence property :username, :string, :length => 5..25 # adds: validates_length_of :username, :minimum => 5, :maximum => 25 property :email, :format => :email_address # adds: validates_format_of :email, :with => :email_address end
-
Quinn Slack January 3rd, 2008 @ 08:26 PM
Re: this code
class Zoo property :name, :string, :nullable => false, :default => "Zoo" end
It seems to me that has one foot in the database world and one foot in the Ruby world. A "string" is a Ruby thing, while the concept of "null" is a database thing. I think consistency would be better. What about :nillable? Or :not_nil?
-
Sam Smoot January 5th, 2008 @ 11:24 AM
Quinn: I see your point... but the :default is database-side as well. If you wanted a Ruby default you'd just overwrite #initialize.
So... I don't know that I'm in favor of doing anything about it right now unless we can think of a consistent idea for what a Property represents.
To me it's basically all about the database except for the first argument (:name in your example).
-
David Lee January 6th, 2008 @ 03:28 AM
I think properties are neither database-side nor ruby-side but business-logic.
This follows closely with what a datamapper is defined to be by martin fowler:
http://martinfowler.com/eaaCatal...
(A mapper "that moves data between objects and a database while keeping them independent of each other and the mapper itself")
Note that the mapper is not the object. Instead, it connects the object to a (relational) database.
So by definition, the mapper itself needs to be able to understand both the object (a business model object in our case) and the database.
That's why we also have things like 'check', 'reference', 'key', to describe the database side, while not having explicit 'associated_model_id'. We instead do 'has_many :associated_models' to describe the business model object.
The thing is, 'string' does not represent the Ruby object 'String' but rather the business idea of a string of characters.
Ruby is just a way to describe the business model that we have, and the business model shouldn't conform to Ruby. By this, I mean that we should call properties "properties" instead of "instance variables," and properties should be defined as they currently are, instead of in the 'initialize' method.
However, for consistency (for the purpose of "the principle of least surprise"), I think it would be best to conform to database terminology, or at least support both:
property :name, :string
property :name, :varchar
property :name, :nullable => false
property :name, :nillable => false
-
Sam Smoot January 7th, 2008 @ 09:03 PM
David, your description of the situation sounds good to me. I guess I can live with aliased options. Kind of a POLS thing I suppose.
Maybe an aliasing Hash might be nice so we could do something like this:
h = AliasingHash.new(:nullable => true) h.alias(:nullable => :nillable) h[:nillable].should eql(h[:nullable])
Or something like that anyways...
I don't want to bloat things with all sorts of special-cased bits of code, but wanting to alias option keys seems a common enough use-case, and messy enough inline implementation, that a specific class for it might be handy.
-
Elliott Mason February 11th, 2008 @ 06:36 PM
class Zoo property :name, :string, :nullable => false, :default => "Zoo" end
I don't like how this adds a validation for me. Here's the problem I'm running into: say I have a column that is a counter like posts_count, and it defaults to 0. Under no circumstances would I want a value in that column to be nil, so to cover my butt I set :nullable => false on that property. Unfortunately, with the current behavior of DataMapper, when I try to save an object without setting its posts_count manually, I get a validation error; posts_count must have a value before being saved, even though it's going to receive that value automatically once it is saved. Ideally, it should be saved and the database will take care of automatically setting posts_count to zero upon being saved.
One of the main things that turned me off of Rails migrations is they didn't give me enough control. At the end of the day I was going into my databases and fixing up columns and making them more specific; making sure certain columns were not-null and that I wasn't using integers where I could use tinyints and that my varchar columns weren't longer or shorter than necessary and that I was using a char column for hashed passwords since they had a definite length, and so on. DataMapper exacerbates this problem because it would destroy all that fine-tunning every time I changed my schema and automigrated.
I think the assumed-validations thing is an OK idea and I was excited about it until I realized some of the ways it could make things difficult. I'd rather just set the validations for myself or at least have it so that I could set a property to not assume a validation (something like :validate => false [or maybe even set :validate => true]). I think the property method should be used to define only database schema and validations should contain the logic for whether or not a record gets inserted/updated.
-
Matt March 15th, 2008 @ 03:31 PM
What about going one step further and allowing domain constraints to be defined, much like the in syntax,
property :name, :string, :nullable => false, :default => "Zoo", :in => ['Zoo', 'Zoo2', 'Zoo3']
which would add the SQL
CREATE DOMAIN zoo_name as VARCHAR NOT NULL DEFAULT 'Zoo' CHECK (VALUE IN ('Zoo', 'Zoo2', 'Zoo3'))
What are your thoughts?
-
Matt March 15th, 2008 @ 03:55 PM
Well, this is actually be:
when creating table: name VARCHAR NOT NULL DEFAULT 'Zoo' CHECK (name in('Zoo', 'Zoo2', 'Zoo3'))
-
Sam Smoot March 17th, 2008 @ 10:15 AM
Matt,
That's the eventual goal (property declarations to flow down into database constraints). So yeah, I'd like to support that.
On the other hand, I'd really like to push the idea of ContextualValidations, which is difficult with the inline declarations, so I don't think the inlines should be the end-all, be-all way to validate. More of a convenience for the most obvious declarations.
-
David Lee March 17th, 2008 @ 02:29 PM
What do you think about using the NotNaughty plugin that budded off from the sequel project?
-
Dan Kubb (dkubb) April 15th, 2008 @ 03:34 AM
- Milestone cleared.
-
Sam Smoot April 27th, 2008 @ 09:46 PM
- State changed from open to resolved
Ok, most of the work discussed here is actually done. I'm closing this ticket since if there's any specific requests we want addressed aside from that, it's probably best for a new ticket since this one covers like a dozen different ideas. ;-)
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
People watching this ticket
Tags
Referenced by
-
123 auto_validations? I think you meant to link to #74 where the validation di...