Hi all :)
Brought this issue to you from here: https://github.com/rails/rails/issues/9362
Problem is, that rails validations as they are now have a dual nature, they are something that:
- helps keep the basic model data integrity (model concept, validate uniqueness of email on user for purpose of password reset, for example)
- is instrumental in making a particular thingy in a particular controller go red if it isn't clicked (controller / view concept, password_confirmation matches password, for example)
and this creates problems.
For example, imagine a hypothetical case where a user may enter his password either through password/password_confirmation or through submitting the salt & hash.
The crypted password and salt fields get presence validators on them because it makes no sense not to have them, this is a model thing, it's also a user input on another form, yet more reason to handle it as a validator and not as a not null constraint or something equally restrictive.
The password (and especially) password_confirmation fields only make sense on the one form that handles user input through them (and consequently acceptance test of that form), but they force you to jump through hoops in the unit tests and in the form that doesn't need those two virtual fields to create a new user record.
This is just a simple and silly example, things get a lot more twisted when porting legacy apps where you need to maintain exact frontend behaviour as well as vaguely similar db structure so mapping can be done successfully.
~~~~~~~~~~~~~~~
Tl;dr bottom line is that validators are model concepts used to do stuff in view/controller.
While this is conceptually a pretty clear MVC violation, it works great for simple CRUD and even more complex cases, as long as the (controller) input attributes are consistent, I don't think this should change, it's pretty KISS for most purposes.
However, when controller input attributes aren't consistent then usual smells of breaking MVC start emerging: from increasing complexity and variety of factories in unit tests to increasing "validates :if => ...." and factory-for-controller method bloat in the model.
One solution would be to implement a callback injection mechanism that can be applied to the instance and not to the class, for example:
https://gist.github.com/bbozo/5006180
This would allow us to handle highly specific controller-introduced validators inside the controller and without adding unnecessary bloat in other areas (usually in unit test factories and with_options :if => some_roundabout_way_of_detecting_which_controller_youre_on block spam in the model).
--Another possibly more complicated solution would be to start working in direction of making validate* methods available on the instance level, not sure what would be a KISS way of doing this though.
Thanks for listening :) Thoughts?
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-co...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.
Visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
However, the form class approach seems The Way to go in general - it definitely feels cleaner, I'm just not 100% bought its the way to go in this particular case, too many special snowflakes. Also, the form class approach seems both dispersed and repetitive in the attribute list mantra department.
At the moment for any given controller action you list the attributes in the form builder, then vast majority of them get listed in the strong_params permit(*args) method, then they get repeated in the delegator/accessor dance + model integration boilerplate in the form class and a part of all of this is already implemented in the model, all of it is quite monotonous, verbose and prone to copy/paste/type errors - and all of this to plug one additional validator in,
while it is cleaner then shoehorning validators onto the instance and watching them interact with model validators with funny side effects in views ("oops you missed 20 fields" on a 5-field form, for example), it does feel kind of fishy.
There's a definite smell about it, it feels un-rails-ish and I can't shake away the thought that some of these things can be unified / dryed up with better organization of the way model, controller and view interact, perhaps the most obvious point would be stronger coupling between the form builder class (from the view) and the form class (from the controller) - after all,
Thoughts?
@Nick, you mentioned that there are gems that tackle this issue?
@Mrloz, "validate: false" has an unwanted side-effect of skipping *_validate hooks which often end up holding generator methods, this is an antipattern though, one of the ways people go around the "validator in form + multiple form inputs" issue while blindly sticking to the "thin controller, oh boy is that one FAT model" principle
Thanks,
Borna