[dm-validations] Ability to disable all auto_validations and | or have dynamically evaluated messages

16 views
Skip to first unread message

heda

unread,
Jan 13, 2009, 5:57:38 PM1/13/09
to DataMapper
Hi all.

Just wondering if anyone has given any thought to a way to disable all
auto_validations for a model? It might be handy in alot of
circumstances rather than putting :auto_validation = false on every
property.

Something like the following?

class ValidateModel
include DataMapper::Resource

disable_auto_validations

property :id, Serial
property :name, String, :nullable => false
....
....
end

The other feature i was thinking about is dynamic message evaluation.
I ran into the problem where i needed the wording of the message to
change depending on the state of some other fields (the actual field
name was far too generic, designed to store a value which is slightly
differently worded in different contexts. Lets say there was a
reference model 'Period' which held Daily, Weekly, BiWeekly or Monthly
etc and some other model with a belongs_to on it

Being able to say the following would be nice

property :frequency, Integer, :nullable => false, :messages =>
{ :presence => lambda {"Cannot have empty value for #{reference.name}
status"} }

It might also be a fantastic help from a I18n point of view ??

Any thoughts on this?

Thanks!
Garrett

Michael Klishin

unread,
Jan 13, 2009, 6:32:45 PM1/13/09
to datam...@googlegroups.com

On 14.01.2009, at 1:57, heda wrote:

> Just wondering if anyone has given any thought to a way to disable all
> auto_validations for a model? It might be handy in alot of
> circumstances rather than putting :auto_validation = false on every
> property.


Do you have ideas for syntax? Will simple disable_auto_validations!
class method be good enough if added?

MK

heda

unread,
Jan 14, 2009, 3:38:44 AM1/14/09
to DataMapper
I guess a better idea might be to use it as a block

class Model
include DataMapper::Resource

property :id, Serial

without_auto_validations do
property :x, String
property :y, String
end

property :name, String
end

Any thoughts?

On Jan 13, 11:32 pm, Michael Klishin <michael.s.klis...@gmail.com>
wrote:

Michael Klishin

unread,
Jan 14, 2009, 5:34:28 AM1/14/09
to datam...@googlegroups.com

On 14.01.2009, at 11:38, heda wrote:

> I guess a better idea might be to use it as a block
>
> class Model
> include DataMapper::Resource
>
> property :id, Serial
>
> without_auto_validations do
> property :x, String
> property :y, String
> end
>
> property :name, String
> end
>
> Any thoughts?


What if we just add something like default_property_options? It can be
used just like
default_repository class method. This would be much simpler to
implement and to follow
(since scope does not change).

Then each property call will simply merge given values with a hash of
defaults you defined on your class.
It won't affect performance either, because it is a boot time code, so
we can extend it to idea of contexts used
by other parts of DM.

What do you think?

MK

heda

unread,
Jan 14, 2009, 5:42:02 AM1/14/09
to DataMapper
Hey Michael

Yeah, I see what you're saying. default_property_options should
probably be a block though rather than a method to allow different
sets of defaults

I literally finished doing a without_auto_validations block moments
before I saw your reply so I uploaded it to basecamp anyways

http://datamapper.lighthouseapp.com/projects/20609-datamapper/tickets/766

On Jan 14, 10:34 am, Michael Klishin <michael.s.klis...@gmail.com>
wrote:

Michael Klishin

unread,
Jan 14, 2009, 5:49:14 AM1/14/09
to datam...@googlegroups.com

On 14.01.2009, at 13:42, heda wrote:

> Yeah, I see what you're saying. default_property_options should
> probably be a block though rather than a method to allow different
> sets of defaults


block will sure give you more flexibility, but how often would you
need it?
I personally have an app with 50+ models and I never used many sets of
default values,
usually just one, that I already implemented as
default_property_options in a plugin not yet open sourced.

MK

heda

unread,
Jan 14, 2009, 5:54:14 AM1/14/09
to DataMapper
Humn,

i've already got a project where I could use atleast two blocks of
default options in more than one model. it would certainly make them
arrid extra-DRY!

I completly agree that we should open this up, away from without_*
towards a complete options scope

On Jan 14, 10:49 am, Michael Klishin <michael.s.klis...@gmail.com>
wrote:

heda

unread,
Jan 14, 2009, 5:56:08 AM1/14/09
to DataMapper
Thing is though, either default_property_options or a
with_property_options {:x => :y, :a => :b} do block is a dm-core
change though right?

On Jan 14, 10:49 am, Michael Klishin <michael.s.klis...@gmail.com>
wrote:

Michael Klishin

unread,
Jan 14, 2009, 6:01:56 AM1/14/09
to datam...@googlegroups.com
On 14.01.2009, at 13:54, heda wrote:

> i've already got a project where I could use atleast two blocks of
> default options in more than one model. it would certainly make them
> arrid extra-DRY!


Alright I am convinced about block form. Next question is, I am going
to add it
to dkubb/dm-core, is it fine with you, or you want a backport to sam/
dm-core?

Dan's tree may or may not have a work-in-progress refactorings and
maybe it'd be
better to go with a stable/old tree if you don't want to be an "Early
Adopter" movie start ;)

MK

Michael Klishin

unread,
Jan 14, 2009, 6:02:49 AM1/14/09
to datam...@googlegroups.com

On 14.01.2009, at 13:56, heda wrote:

> Thing is though, either default_property_options or a
> with_property_options {:x => :y, :a => :b} do block is a dm-core
> change though right?


Yes, it belongs to dm-core since it is no longer limited to
validations (and that is my whole idea).

MK

heda

unread,
Jan 14, 2009, 6:06:31 AM1/14/09
to DataMapper
Superb!, dkubb/dm-core is perfect!

Make sense to put it on the edge since its a new feature anyways

On Jan 14, 11:02 am, Michael Klishin <michael.s.klis...@gmail.com>
wrote:

heda

unread,
Jan 14, 2009, 6:08:42 AM1/14/09
to DataMapper
On another note. Have you any concept objections to dynamic eval
messages?

I was going to have a look and see at valid? time if the :message is a
Proc and just execute it within the models scope?

On Jan 14, 11:02 am, Michael Klishin <michael.s.klis...@gmail.com>
wrote:

Michael Klishin

unread,
Jan 14, 2009, 6:26:09 AM1/14/09
to datam...@googlegroups.com
On 14.01.2009, at 14:08, heda wrote:

> On another note. Have you any concept objections to dynamic eval
> messages?
>

"Dynamic eval" gave me some creeps initially (I appreciate having
as little magic as possible in the code), but if what you mean is

> I was going to have a look and see at valid? time if the :message is a
> Proc and just execute it within the models scope?


just a way to do

class SubversionOperation < ScmOperation
#
# Validations
#

validates_present :network_connection, :when
=> :committing, :message => proc { |record| "what you think I am, a
Git?!" }
end

then keep in mind message already handles this case:

validates_present :prop, :when => [:update, :create], :message => {
:create => "message for create context",
:update => "message for update context"
}

That is, you need to keep multiple contexts in mind, and thus think
about keeping code simple. I call this feature
"callables expansion" usually. But I am all for it.

I am in the process of rewriting dm-validations spec suite from
scratch, so I'd take on it as soon as I finish with most of it. I am
done with 3 validators
already, and have pretty good set of fixtures to get up to speed with
those left.

MK

heda

unread,
Jan 14, 2009, 6:35:20 AM1/14/09
to DataMapper
Yeah, the proc is what i'm going after

validates_present :network_connection, :when
=> :committing, :message => proc { |record| "what you think I am, a
Git?!" }

the context messages don't really cover it for me as the
messagechanges not on context but the state of other properties on the
model.

Just to refer back to the example I gave before of a model which
represents time spans (Daily, Weekly, Monthly, Quaterly, Yearly, etc)
and then a model which references a time span and has a property
frequency, the error message would need to change to suck in the name
of the time span => "Please supply a #{time_span.name} frequency for
this job"....

class TimeSpan
property :name, String
end

class Job
property :frequency, Integer, :message => proc {|r| "Please supply a
#{time_span.name} frequency for this job"}
property :time_span_id, Integer

belongs_to :time_span
end

On Jan 14, 11:26 am, Michael Klishin <michael.s.klis...@gmail.com>
wrote:

heda

unread,
Jan 14, 2009, 6:38:59 AM1/14/09
to DataMapper
I can also immediatly see an advantage here for translations

property :name, String, :nullable => false, :messages => {:presence =>
proc {|r| translate("Please supply a name") }

There may be other way of doing this translation already but it came
to mind as a solution to a translation problem

Earle Clubb

unread,
Jan 14, 2009, 9:08:57 AM1/14/09
to datam...@googlegroups.com
So what would the usage look like in the block form?

Earle

heda

unread,
Jan 14, 2009, 9:13:39 AM1/14/09
to DataMapper
I'd imagine (though Michael can verify this) that the block should
look something like this

with_default_options {:precision => 8, :scale => 2, :nullable =>
false} do
property :minimum, BigDecimal
property :maximum, BigDecimal
end

with_default_options {:size => (10..100), :nullable => false} do
property :firstname, String
property :lastname, String
end

Michael Klishin

unread,
Jan 14, 2009, 10:01:06 AM1/14/09
to datam...@googlegroups.com

On 14.01.2009, at 17:13, heda wrote:

> I'd imagine (though Michael can verify this) that the block should
> look something like this
>
> with_default_options {:precision => 8, :scale => 2, :nullable =>
> false} do
> property :minimum, BigDecimal
> property :maximum, BigDecimal
> end
>
> with_default_options {:size => (10..100), :nullable => false} do
> property :firstname, String
> property :lastname, String
> end


Correct

MK

Adam French

unread,
Jan 14, 2009, 10:04:33 AM1/14/09
to datam...@googlegroups.com
Avoid needless complexity

opts = {:size => (10..100), :scale =>2, :nullable => false}
property :maximum, BigDecimal, opts
property :minimum, BigDecimal, opts

===
~Adam

heda

unread,
Jan 14, 2009, 10:18:40 AM1/14/09
to DataMapper
too messy when you have sets of options

opts = {:auto_validation => false}
opts_string = opts.merge({:size => 50})
opts_decimal = opts.merge({:precision => 10, :scale => 4})

property :firstname, String, opts_string
property :lastname, String, opts_string

property :minimum, BigDecimal, opts_decimal.merge({:nullable =>
false})
property :maximum, BigDecimal, opts_decimal

=====

much cleaner and easier to read with something like

with_default_options {:auto_validation => false} do

with_default_options {:size => 50} do
property :firstname, String
property :lastname, String
end

with_default_options {:precision => 10, :scale => 4} do
property :minimum, BigDecimal, :nullable => false
property :lastname, BigDecimal
end

end

On Jan 14, 3:04 pm, "Adam French" <afcoo...@gmail.com> wrote:
> Avoid needless complexity
> opts = {:size => (10..100), :scale =>2, :nullable => false}
> property :maximum, BigDecimal, opts
> property :minimum, BigDecimal, opts
>
> ===
> ~Adam
>
> On Wed, Jan 14, 2009 at 9:01 AM, Michael Klishin <
>

Michael Klishin

unread,
Jan 15, 2009, 6:48:49 AM1/15/09
to datam...@googlegroups.com
I lean towards what Adam suggested: if there is a way already to do it
effortlessly, maybe even
it is an eye soar to some, no need to add more code to -core.
More code means more bugs, slower execution
and more spec examples to add to some (at first glance unrelated)
places. Yes, I am totally
merb-brain-damaged and all that.

This particular feature can be a plugin. It would require some simple
refactoring in -core,
but this is what -core is all about: being open for extension.

What we end up with for now:
http://datamapper.lighthouseapp.com/projects/20609-datamapper/tickets/771

On 14.01.2009, at 18:18, heda wrote:

> too messy when you have sets of options
>
> opts = {:auto_validation => false}
> opts_string = opts.merge({:size => 50})
> opts_decimal = opts.merge({:precision => 10, :scale => 4})
>
> property :firstname, String, opts_string
> property :lastname, String, opts_string
>
> property :minimum, BigDecimal, opts_decimal.merge({:nullable =>
> false})
> property :maximum, BigDecimal, opts_decimal
>
> =====
>
> much cleaner and easier to read with something like
>
> with_default_options {:auto_validation => false} do
>
> with_default_options {:size => 50} do
> property :firstname, String
> property :lastname, String
> end
>
> with_default_options {:precision => 10, :scale => 4} do
> property :minimum, BigDecimal, :nullable => false
> property :lastname, BigDecimal
> end
>
> end


MK

heda

unread,
Jan 15, 2009, 12:09:01 PM1/15/09
to DataMapper
I can respect that...i'll write my own monkey patch so - you mentioned
previously you had already created a default_options method that you
were using privately - could I be so cheeky as to ask for permission
to use it as a basis for my own effort?

Also, what are your thoughts on message evaluation? I was looking at
this last night and in the current source it looks like the
generic_validator is where it would need to go to be consistent and
dry across all validations (def add_error_message i believe). Also,
I'm not sure passing the record into the message proc is the right way
to go?? This limits you to the public properties on the record when in
alot of cases its probably advantegous to have some private or
protected methods to generate message fragments.

On Jan 15, 11:48 am, Michael Klishin <michael.s.klis...@gmail.com>
wrote:
> I lean towards what Adam suggested: if there is a way already to do it  
> effortlessly, maybe even
> it is an eye soar to some, no need to add more code to -core.
> More code means more bugs, slower execution
> and more spec examples to add to some (at first glance unrelated)  
> places. Yes, I am totally
> merb-brain-damaged and all that.
>
> This particular feature can be a plugin. It would require some simple  
> refactoring in -core,
> but this is what -core is all about: being open for extension.
>
> What we end up with for now:http://datamapper.lighthouseapp.com/projects/20609-datamapper/tickets...

Adam French

unread,
Jan 15, 2009, 1:46:56 PM1/15/09
to datam...@googlegroups.com
I do appreciate that your trying to keep the code as dry as possible, but I personally prefer to keep the property declaration part (and association part) of my DataMapper class definitions as declarative as possible.

For example:

# ===========
# cleaner
 
opts = {:auto_validation => false, :size => 50}
property :firstname, String, opts
property :lastname, String, opts
 
opts = {:auto_validation => false, :precision => 10, :scale => 4}
property :minimum, BigDecimal, opts.merge({:nullable => false})
property :maximum, BigDecimal, opts
  
# ===========
# more typing at first, but easier to maintain, more declarative, and more glance-able
# (Adam's preference)
 
property :firstname, String, :auto_validation => false, :size => 50
property :lastname, String, :auto_validation => false, :size => 50
 
property :minimum, BigDecimal, :auto_validation => false, :precision => 10, :scale => 4, :nullable => false
property :maximum, BigDecimal, :auto_validation => false, :precision => 10, :scale => 4

((if the formating or line-endings got messed up, check out http://gist.github.com/47524 ))

I personally prefer the latter because it's "stupid-proof" and makes everything as obvious and accessible as possible.  The former may have been less typing up-front, but you can't really glance-over it and know what's going on with each property....you have to glance up to the 'opts' variable to get the list of property options rather than them being inline with the property.

But really it's all up to the person writing the code and their preferences.  As michael points out, adding the default_options block method you proposed can be a plugin lets people opt (har) into using it if they want to.  When there's enough demand to move default_options into -core, talk with dkubb and he'll make it happen.
===
~Adam

Sam Smoot

unread,
Jan 15, 2009, 2:18:08 PM1/15/09
to DataMapper
On Jan 14, 4:54 am, heda <garr...@techgest.com> wrote:
> i've already got a project where I could use atleast two blocks of
> default options in more than one model. it would certainly make them
> arrid extra-DRY!

Just to butt-in. ;-)

Nothing to do with DRY. In practical terms, DRY basically means "use
constants". So instead of using a Literal to set a tax-rate in a dozen
places in your app, you set a constant, and use that.

You might bend these default options to imply DRY-ness if the DRY-
ability were based on the Type of the Property instead of the Class
the property was declared in. But then you could just create a quick
custom type to set a few default options and forgo the load/dump
declarations. Exactly like the Text type.

Sorry, pet-peeve of mine, but DRY has nothing to do with how much
you're typing, or whether you're copying-and-pasting and everything to
do with Domain knowledge. If two different String properties that just
happen to share :nullable => false can't reasonably be framed as
representing the same knowledge, then eliminating the duplication in
typing isn't an example of DRYness, it's an example of minimizing
keystrokes, which is often at odds with readability and counter to the
goal of DRY which is simply to excise fragility and lower the risk and
effort required to accommodate change.

/end rant. ;-)

-Sam

heda

unread,
Jan 15, 2009, 2:27:52 PM1/15/09
to DataMapper
=begin semi-counter rant

dry-ness to me is the ability to express a concept which is common
between various parts via a single point, in some cases that means a
constant, in many other its does not

i agree its not about minimizing keystrokes, i agree it is about
maintaining clarity of code and improving the concesity of conceptual
expression

=end

Sam Smoot

unread,
Jan 15, 2009, 3:22:48 PM1/15/09
to DataMapper


On Jan 15, 1:27 pm, heda <garr...@techgest.com> wrote:
> =begin semi-counter rant
>
> dry-ness to me is the ability to express a concept which is common
> between various parts via a single point, in some cases that means a
> constant, in many other its does not
>
> i agree its not about minimizing keystrokes, i agree it is about
> maintaining clarity of code and improving the concesity of conceptual
> expression
>
> =end

:-)

I think you undermine your argument with your last statement though.
What concept are you trying to express? What conceptual (and
importantly, Business Domain) allegiance do first_name, last_name and
minimum fields share?

When "The Pragmatic Programmer" came out, C, Java and Visual Basic
dominated. Java without closures. Visual Basic with very rudimentary
support for inheritance or classes. Only C macros could come close to
the sort of constructs now commonly presented in Ruby as measures to
ensure DRYness.

I think it's a lot easier to frame the definition in the context of
it's time: A developer using Java servlets or an ASP developer, and
what sorts of things they might have been doing that prompted the
advice.

It really comes down to this: Without a unifying concept of the
knowledge you're trying to canonically represent, you can't claim
DRYness. A default of 50 characters for both a first_name and a
last_name is not domain knowledge. Odds are, as the domain is refined
it's seems likely the with_options helper would need to be removed
down the line so each piece of knowledge can be represented
accurately.

Enough with my hijacking. ;-) But yeah, I don't have much community
experience outside of Ruby these days, but it's my impression the
repurposing of "DRY" is a Rails influenced concept, and it's
unfortunate that the valuable Domain Knowledge discussion seems mostly
lost in the superficial and low-value (as far as productivity,
maintainability, business-value) concept of beauty over Design.

It's a distraction that encourages a race-to-the-bottom that
emphasizes style over substance; where Domain Driven Design (DDD, the
first/true one, not the silly development methodology discussion aka
"d3") is an after-thought. It's a road leads to Ruby as the next big
Cold Fusion instead of the next big Java (IMO).

-Sam

PS: Yeah... uh... sorry for the de-rail.

heda

unread,
Jan 15, 2009, 3:38:14 PM1/15/09
to DataMapper
:'-( i really don't want to get into another one of these "what
exactly does a term mean and does it apply absolutely and completely
in this scenario". I'm making it a rule from now on that I'm only
going to subject myself to them when alcohol is available.

Hows about, for now, you define it in a way that works for you, I'll
define it in a way that works for me, we agree to agree on most of the
details and agree to differ some of the details.

Next time you're in Dublin give me a call, we can have a pint or ten,
sit down as men do and discuss important things (like the nature of
DRYness).
Reply all
Reply to author
Forward
0 new messages