Best Practices: Splitting the "view model" from AR model

All,

I’m starting to see view state information creeping into my model class.
For example, I have text fields in my view that need to be set a certain
way depending on whether or not a checkbox is checked. And while the
values of these text fields ultimately do represent database columns
that are related to the backing AR object, the text_field values also
represent attributes on a “text field” object in my view?

Is anyone splitting out their view model and then handling the transfer
of those values into an AR object in their controller? It seems to me
that it would further decouple the view from the underlying AR (and
hence, DB) representation.

Hope this makes sense,
Wes

Wes:

It depends. In this case, I’d argue that something like this belongs in
the
model as a validation

Here’s an example of a validation I did for my project management
system.

validates_presence_of :fixed_bid_amount
:if => Proc.new{|p| p.fixed_bid == true}

Even though it seems coupled to the view, it’s not… it’s actually a
business rule. In the above example, I want to force validation (prevent
it
from saving) when the fixed bid amount field has been left blank, but
only
if they have marked the project as a fixed bid.

If I were to create a new project using an XML-based request instead of
a
web form, I would still want this rule to be enforced. Therefore, it
belongs
in the model.

Brian H. wrote:

Wes:

It depends. In this case, I’d argue that something like this belongs in
the
model as a validation

Here’s an example of a validation I did for my project management
system.

validates_presence_of :fixed_bid_amount
:if => Proc.new{|p| p.fixed_bid == true}

Even though it seems coupled to the view, it’s not… it’s actually a
business rule. In the above example, I want to force validation (prevent
it
from saving) when the fixed bid amount field has been left blank, but
only
if they have marked the project as a fixed bid.

If I were to create a new project using an XML-based request instead of
a
web form, I would still want this rule to be enforced. Therefore, it
belongs
in the model.

This is a good example. In this case, your “fixed_bid” boolean, which I
assume is a model attribute, maps directly to a checkbox in your view.

In my case, I have a checkbox which represents an option to take a
shortcut to some field value definition, and this checkbox is definitely
not part of the model. In fact the fields that it’s dealing with aren’t
in the model either. They are view-specific representations of part of
the model as well.

I feel like what should be done here is to create a Facade object
“around” the model object that provides all of the non-model related UI
logic, but is capable of passing through to/from the model object when
model fields are displayed/received without modification in the view.

Another issue I’m noticing is that I’m having to do this in my
initialization of my model in order to correctly initialize view
components without overwriting DB provided values when I instantiate
this view object. For example:

self.FAX = contact.FAX if self.FAX.nil?
self.EMAIL = contact.EMAIL if self.EMAIL.nil?

When the object is created from nothing, I want to default certain
attributes. When the object is created from the DB, I don’t want to
default the attributes, I want to get the correct values from the DB.

If I were dealing with a separate form object, I could just default
fields and then they would just become attributes on a successful
save.

Make sense? Or am I overcomplicating things?

Wes
Make sense?

As I consider what I just suggested above a little more, I see that if I
went all the way with this idea, I would end up with a plain vanilla
AR::Base descendant class and some other object, which I’m referring to
as the “view model” and then some controller activity to copy all of the
field values from the “view model” into the AR-model.

I worked on a project with a scheme like this and thought it was silly
:). I had just forgetten.

I guess if you look at it in the sense that your facade methods in your
AR model are clearly not part of the model since they have to exist in
the first place (AR doesn’t “give them to you for free”), it is
acceptable that they live in the same class.

In fact, perhaps it is more correct, and meaningful(?) to think of the
AR::Base class as the model and then my descendant of it as the view
model? This makes sense because if I had a trivial view, I would just
need access to the AR model, which is exactly what

class XYZ < ActiveRecord::Base
end

gives you.

Here XYZ is a view model that represents a trivial view. However, when
the view model becomes “untrivial,” then I begin to flesh out my XYZ
view model.

Wes

Brian H. wrote:

Right on.

Isn’t it neat how just by talking about these kinds of things we often
find
our own answers? :slight_smile:

Sure. Not completely sold on what I said above - however, good stuff to
consider.

Just trying to get my head around correct approach.

Wes

Right on.

Isn’t it neat how just by talking about these kinds of things we often
find
our own answers? :slight_smile:

At 09:06 PM 7/17/2006, you wrote:


Sure. Not completely sold on what I said above - however, good stuff to
consider.

Just trying to get my head around correct approach.

you might find
http://en.wikipedia.org/wiki/Presentation-abstraction-control an
interesting read. then try
http://www.google.com/search?hl=en&q=mvc+pac&btnG=Google+Search

thanks


vice-chair http://ocjug.org/

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs