Usually, only good things are said about validation in the rails. Today we will talk about some situations where the system fails.
Situation once
When registering a user, we normally want to confirm the password. No problem, add: confirmation => true. After some time, the site has a mobile application in which registration is also implemented, but there is no longer any confirmation of the password. What to do in this case?
solution under the cut
')
The most popular answer: in the controller, manually set the password_confirmation. Hold on What does password verification have to do with a user model? What is password verification in general? A confirmation email (yes, some do and so)?
Situation two
Same registration. Email as usual mandatory. Product Owner adds social integration task. by networks. Looking at the authorization documentation via Twitter, we understand that we can not see the email. Someone, of course, after authorization will ask to enter an email, but in our case the manual is against. It is necessary to authorize without an email and a period, but at the same time the registration form must require an email in any case. And what to do in this case?
Answers that I heard:
- skip validation in registration.
- We put a fake email - qwerty@twitter.fake.com.
- by hacks, we cut the error message from errors and pretend that everything is OK 0_o.
- Depending on the incoming parameters inside the model, custom validation is triggered.
Is email required for a user model with such requirements? Answer: No, our application should work correctly even in its absence.
But what about the registration form?
The truth is somewhere near
If you look closely at the first and second situations, it becomes clear that form is something more than an html piece (by the way, there is no html in api, but there is also a “form” there). So, it is the form in specific situations that should validate the confirmation of the password, the presence of an email, since This behavior is not a model, but a specific form in a particular representation. The funny thing is that there is no such problem in many other frameworks. The form model is in
django ,
zend framework ,
symfony ,
yii . And there are even
attempts to do this in rails. You can also try to implement this functionality through ActiveModel.
What personally grieves me in this whole story is the fact that the rails developers themselves show absolutely the wrong way to solve these problems. They add validators like: confirmation => true, actually violating the basic mvc principle: the model does not depend on the presentation.
We have found a solution for our projects and so far it suits us as a whole, and at the same time solves another
known problem . It lies in the fact that for specific forms we create the heirs of our models and work actually through them. Of course, this is the most natural hack, but in trying to write separate forms, I ran into difficulties in implementing nested forms and postponed this matter until better times.
1. Make in apps daddy types.
2. Add base_type.rb there
module BaseType extend ActiveSupport::Concern module ClassMethods def model_name superclass.model_name end end end
3. Create the desired type. Example:
class UserEditType < User include BaseType attr_accessible :first_name, :second_name validates :first_name, :presence => true validates :second_name, :presence => true end
So with the help of simple inheritance, we solved the problem of custom validation depending on the current view and requirements for it. The truth will still have to correct the strings of some gems in the class name, not model_name (carrierwave, for example, it builds paths based on the class), but so far this has been resolved quite easily.
Why is it called Type and not Form? In api, there is no form as such, but the requirements are the same. And the name Type is taken from the symfony framework.
From the last example, you can see that another problem related to attr_accessible is also being solved. Of course, you can argue that you can use the: as option for this, but in reality it breaks the encapsulation by adding information about the upper layer to the model.