Did you get to the point where your model is over 1k lines longs and moreover stuffed with various concerns? If so – maybe it’s time to think about extracting so called form models (Ruby/Rails community always have fancy names for most simple things :p).
What is a form model? It’s simply a Ruby class (d’oh) that encapsulates logic related to a single operation. Dead simple example that comes to mind is some kind of a sign up process that exists in almost every web application.
How to do it?
If you are using Rails 4 you can simply include
ActiveModel::Model in your ruby class to benefit from validations, callbacks and all that useful stuff. There are also alternatives like reform or active_type – personally I really like the second one as it’s really small with no extra dependencies.
So let’s say I have a profile form in my app in which user can change bunch of different stuff. It’s quite a big form, it allows changing many things, it accepts nested attributes for one or more associated models – in general my
User model have a lot of logic related to that form. Let’s create new form object using
active_type and simply move some logic from one class to another.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
And now in where you used
User.find(x) to set a
@user for your
form_for you can simply use
User::ProfileForm.find(x) and it will still work (
model_name still points to
User so there is need to change params format in your controller).
How is that better?
You moved some code from one class to another one – it this even worth the trouble? I think it is – our main
User model in now thinner, we have a class that is responsible for updating user’s profile, we’re no longer polluting user with bunch of logic that happens only in single place in the application. This logic in not carried away every time you fetch a user from your database.
This can be especially useful if you’re doing things like sending emails after updating some important column. Now you have a callback disaster waiting to happen. One day you run a rake task and without even knowing you send a bunch of emails to your users (been there, done that).
In given example you moved some validation, it’s cool you there is only one place in application where user can update it’s profile. But if suddenly user will be allowed to update profile in another place and you forget to use proper form object you might end up with inconsistent data. If you’re taking logic from
User class you need to make sure if it’s not used in other places in your application.
Watch our for gems that are included in your parent class (of course if you’re using underlying activerecord object).
paper_clip for example relies on class name (not model name) when saving attachments so in given example your would have to explicitly set
1 2 3 4 5 6