I’d go with a separate form object but that’s just “me” My friend Evan Light just recently pointed me to GitHub - ClearFit/redtape: An alternative to accepts_nested_attributes_for that doesn't tightly couple your view to your model
You’re right,
remaining coupled to the model, even in this case, brings more trouble/smell then it’s worth. Redtape is an interesting take on the problem, but at least at first glance doesn’t feel like a step in the right direction: model coupling is still strong, it doesn’t seem to resolve the validator duality (and view-model coupling it generates), and I’m not a fan of “mapping frameworks”.
The form class solution should be something that responds to new, valid, save and errors. The input attributes of the form object initializer would ideally have some sound default mapping to the underlying model / models, both in terms of getters/setters and in terms of delegating validators and the expected result of the form class would a valid (set of) model instance(s).
For example,
if Model is a model class and Form is a straight&simple form class of that model and Form validates attributes a and b, and Model validates attributes b and c, then a Form instance should be valid if and only if both a in Form and b in Model and Form are valid as well as the Model instance itself (this would happen if Form instance doesn’t set up Model instance correctly).
Arguably, it would have access to the controller context, deal directly with the params hash and handle attribute filtering, hopefully making that whole attribute accounting thing a bit dryer, there’s quite a bit of repetitive coding going on atm in that area.
Something in these lines looks like the way to go in the long run, at least for me (if anything meaningful comes up I’ll gemify it). Anyway, this looks like something missing out from rails core, or is at least missing from the general rails ecosystem atm.
Borna
- Parameter filtering is a controller issue. Rails-core proposes strong_parameters and the like, I personally prefer a representer. However, what comes out in the end is a parameter hashed passed to the form object.
- Validating the form by delegating to various models should happen in a separate form object. You’re absolutely right when you say Rails is missing something here.
I made yesterday a small-ish abstract class, which got left in the office -_-, its working something in the lines of Form class sketch · GitHub
Ofc, one can integrate this with form_for to get appropriate helper behavior for read only fields and whatnot
As for the second point:
- Parameter filtering is a controller issue. Rails-core proposes strong_parameters and the like, I personally prefer a representer. However, what comes out in the end is a parameter hashed passed to the form object.
As far as I understood, the strong parameters were implemented to stop people from submitting attributes that were not intended to be changed through this or that particular form on this or that particular controller action, if there is such a thing as a form class then it can just as well be within its domain to explicitly define its input/output which would reduce the attribute list repetition and resolve the issue that strong_parameters want to fix, like in the gist.
Any ideas why any of this could be a bad idea?
Borna