ActiveRecord and Form Data Coupling: A Bad Design

I have to say that after being a Rails user for some time I have grown to really dislike how ActiveRecord (AR) classes - models - are being pushed as the defacto method for getting form data into the DB. The two concepts are completely separate and should be handled by completely different classes.

Anyone who understands Object Oriented Design knows that we separate classes based on functionality and responsibility. An automobile class, for example, would represent something that has wheels and drives; a fixed-wing aircraft class would represent something that flies. Such is the case with AR, it handles the interaction with the database and holds the data, and perhaps has some extra methods that interact with the data it holds. Also, what we see a lot of is having the AR class also handle data coming from a form, which breaks encapsulation. It's like saying that to build the ultimate vehicle would be to put wings on a car because it would be get us in a jiffy whether we had to go short or long distances (a nice idea, but try driving down Broadway with wings spanning forty feet).

The problem with coupling the form and the AR is that it may have very little resemblance to the form that is creating it. I've encountered this quite a bit. For registration (user model) I had to add a number of attributes to the class that had no mapping to the db, that hung around and cluttered up the design tremendously. Furthermore, the need to have those attributes validated compounded the problem further since some could only be validated on create or on update. Also whenever I wanted to save the object when not in form mode i always needed extra code to flag or message the object so that it wouldn't validate itself - a time consuming and unnecessary task.

The ultimate solution was to do what OOD says to do - break out the forms into a completely separate class that handled and validated the form data and then passed the data to the AR object. Needless to say, it took quite a bit of time to do, and I think it's the best solution. I hope that the next versions of Rails will contain some kind of ActiveForm class for the sake of others.

I'm sure we've all run into this at one point or another for non-trivial forms. But, this kind of radical change is best served as a plugin to start. Share your active_form plugin with the world and prove with real code in production that it kicks ass.

One thing I would like to do, for start, is extract some of the common 'model' code out of ActiveRecord into some kind of ActiveModel class. This includes basic validation functionality, as well as callbacks possibly. It's something I may look into later after Rails 2.0 has been released.

You might find the Presenter pattern useful:

Pat

The current design seems "natural" to me because 9x of 10 it's what you want. Form data goes into table either verbatim or with few manipulations. But for that 1x, it's a pain.

I've used my own framework for several years now which had validation coupled to the form-to-table process as well. I also started to get more annoyed when I needed things just a hair outside the norm. Quite recently, I finally decoupled the validation process and forma data storage as you're suggesting so I could accept and validate forms w/o being forced to map that onto a table at that instant. However, I did it in a way that the ORM and validation system did have intimate enough knowledge to still provide that automatic magic with virtually no effort. While that may also be imperfect OOD, it seemed the right thing to do to preserve the magic, yet not be hostage to it as well.

Vague, I know, but just saying that I think a design compromise is both possible and worthwhile.

-- gw