Some thoughts I've been mulling over on validation

36 views
Skip to first unread message

Phil Darnowsky

unread,
May 9, 2013, 12:50:04 PM5/9/13
to boston-r...@googlegroups.com
I have spent what seems to be a disproportionate amount of time over the
past few years wrestling with my ActiveModel/Record validations.

One example: we have a User model, which usually must have an email
address--but under certain circumstances, a User without an email can be
valid. Similarly, we have mobile numbers on our Users (we do stuff with
SMS), and that's usually not required, but sometimes it is.

It's pretty easy, then, for the validation code for a model to turn into
a big mess of special cases and conditionals. Hard to write, hard to
test, hard to understand, easy to write bugs.

So I've been thinking of creating a gem that would let you create
"validation contexts": a way to formalize and reify the idea that
different validations are relevant at different times. Using it might
look like this:

@user.save(in_context: SMSOnlyContext.new)

where SMSOnlyContext is a context that says, essentially, "We only
expect this user to interact with the system via SMS, so email need not
be present, but the mobile number better be."

Have any of you run into similar problems? How did you handle them? Do
you know of anyone who's implemented anything similar?

Thanks,
Phil

Brian Cardarella

unread,
May 9, 2013, 12:53:15 PM5/9/13
to boston-r...@googlegroups.com
Hey Phil,

Strange how you just brought this up. I just released a gem to deal with this:


It draws outside the lines of how Rails devs normally think of building validation models but it definitely solves contextual validation problems.

I have a blog post describing the reasons I just finished writing up 10 minutes ago: http://reefpoints.dockyard.com/ruby/2013/05/09/context-validations.html

I'm eager for feedback.

Dan Pickett

unread,
May 9, 2013, 1:05:57 PM5/9/13
to boston-r...@googlegroups.com
I've thought about this issue as well. Brian's approach is cool, and I find it interesting to see stuff like that in the controller!

My primary direction of thinking has been around mass assignment. I kind of hate strong parameters. 

I think both contextual use cases warrant the use of a form model. This object would be the intermediary between the controller and the model, and would be centrally responsible for populating the actual model with the user supplied data contextually. 


--
You received this message because you are subscribed to the Google Groups "Boston Ruby Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to boston-rubygro...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Brian Cardarella

unread,
May 9, 2013, 1:08:13 PM5/9/13
to boston-r...@googlegroups.com
I address form objects in the blog post. I like the simplicity of strong params and wanted to maintain the same simplicity for context_validations. I do concede that form objects might be necessary for extremely complex cases.

Allen Madsen

unread,
May 9, 2013, 1:08:35 PM5/9/13
to boston-r...@googlegroups.com
The other approach I've seen to handle this is using form objects which have their own validation.



Some gems that try to make doing this simpler are:

On Thu, May 9, 2013 at 12:53 PM, Brian Cardarella <br...@dockyard.com> wrote:

--

Pat Shaughnessy

unread,
May 9, 2013, 1:09:39 PM5/9/13
to Dan Pickett, boston-r...@googlegroups.com
Great idea and article, Brian!

Coincidentally I read a post this morning about something related to "form objects": http://nicksda.apotomo.de/2013/05/reform-decouple-your-forms-from-your-models/

Makes me wonder if validation belongs with the model or the view (form).

- pat

Brian Cardarella

unread,
May 9, 2013, 1:16:30 PM5/9/13
to boston-r...@googlegroups.com, Dan Pickett
I believe that controllers are the context in which you are interacting with the model so at the very least looking at the controller first should be where any contextual events occur.

Dan Pickett

unread,
May 9, 2013, 1:44:04 PM5/9/13
to boston-r...@googlegroups.com
I've been playing with active_attr a lot to see if I can achieve the type of form object I want. It's a great library for creating ActiveModel objects that behave a little closer to ActiveRecord models. 


I can totally see your point, Brian, where it feels like a controller context. I'm really torn on what layer of MVC these objects should reside.

I would welcome/encourage a talk on this subject - we are looking for speakers for June and this could be the makings of an awesome talk!

Best,
Dan

Brice Stacey

unread,
May 9, 2013, 2:08:27 PM5/9/13
to boston-r...@googlegroups.com
ActiveModel already has validation contexts. I just use that.

class User < ActiveRecord::Base
  validates :phone_number, presence: true, on: :sms
end

The following methods will run all general validations, but also those in the given context.

@user.save(context: :sms)
@user.valid?(:sms)

I may use this context when saving SMS preferences, but not for general User persistance (e.g. updating password). It's the same interface used for on create and on update validations, but you can use your own contexts too.


--
You received this message because you are subscribed to the Google Groups "Boston Ruby Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to boston-rubygroup+unsubscribe@googlegroups.com.

Brian Cardarella

unread,
May 9, 2013, 2:08:45 PM5/9/13
to boston-r...@googlegroups.com
After spending the last few months in Ember my thoughts on MVC have definitely been influenced. For better or worse I've begun to treat my Rails controllers more like I do my Ember controllers (Ember controllers are proxies for models). Context is huge in Ember and while Ember itself doesn't have a formal validation library built in the validations people have been implementing tend to be done on the controller instead of the model.

Brian Cardarella

unread,
May 9, 2013, 2:17:41 PM5/9/13
to boston-r...@googlegroups.com
While the word "context" is the same here the application is different. Avoiding monolithic validation rules in the model is the goal.
To unsubscribe from this group and stop receiving emails from it, send an email to boston-rubygro...@googlegroups.com.

Allen Madsen

unread,
May 9, 2013, 2:21:26 PM5/9/13
to boston-r...@googlegroups.com
I fall into the camp of people who think your application should be separated from the delivery mechanism. That is why I would rather have a domain object specify the context rather than the controller which is tied to HTTP. Form objects fit that model very well. 

Ember controllers are more like view models, whereas the routes behave more like a controller.

Robert Thau

unread,
May 9, 2013, 5:17:44 PM5/9/13
to boston-r...@googlegroups.com
Phil Darnowsky writes:
> One example: we have a User model, which usually must have an email
> address--but under certain circumstances, a User without an email can be
> valid. Similarly, we have mobile numbers on our Users (we do stuff with
> SMS), and that's usually not required, but sometimes it is.
>
> It's pretty easy, then, for the validation code for a model to turn into
> a big mess of special cases and conditionals. Hard to write, hard to
> test, hard to understand, easy to write bugs.

FWIW, one way of dealing with this sort of situation is using
single-table-inheritance, which lets you associate more than one Ruby
class (say, BasicUser, AdminUser, etc.) with the rows of a single
table (say, "users"). The subclasses can then have their own
validations.

There are cases that get awkward here, one of which I've actually
illustrated already: if you ever want to upgrade a BasicUser to be
an admin without altering references to that particular "users" row
from elsewhere in the schema, STI forces you to jump through some
really awkward hoops. But if your problem domain is such that you're
pretty sure that won't happen (e.g., a "book" won't *ever* magically
transform itself into a "dvd", even though they're both in the
"merchandise" table), then it can be a pretty nice fit.

(It also separates the validation rules from the mechanics of
implementing the UI --- which means that if you've got multiple
controllers manipulating the same data, you don't have to worry about
whether they're all implementing the same set of rules.)

rst

Brian Cardarella

unread,
May 10, 2013, 10:49:18 AM5/10/13
to boston-r...@googlegroups.com, r...@alum.mit.edu
I try to avoid STI. Under my example there will be table rows likely unused by the STI models. This is not a good way to model data.

Brian Cardarella

unread,
May 10, 2013, 10:51:17 AM5/10/13
to boston-r...@googlegroups.com, r...@alum.mit.edu
Table columns I mean :p
Reply all
Reply to author
Forward
0 new messages