Understanding MVC and relationships among them - any schema?

Hi,

I’m about 1 month into RoR but still haven’t managed to google out
some schematic summary of the RoR philosophy (maybe I’m just rubbish
with google):

  • which function/method goes where (M/C/helper), what is the rule to
    decide
  • how to call function from one to another (from M to C, between two
    Ms, between two Cs, available to all Ms, etc.) and how to pass
    parameters (when to use params[:whatever] and when the variable
    itself). when to use self.function etc.
  • in which case I need to pass @records/@record/records/record

I’m almost always able to google out the particular solution to the
particular problem but still don’t fully understand the logic/
conventions behind. I haven’t come across some complex summary, the
best I got so far is Agile Development book but that didn’t fully
clarify it for me.

Thanks for any hints!

On 6 Jun 2008, at 13:30, pepa007 wrote:

Ms, between two Cs, available to all Ms, etc.) and how to pass
parameters (when to use params[:whatever] and when the variable
itself). when to use self.function etc.

  • in which case I need to pass @records/@record/records/record

These aren’t really rails questions, they’re ruby (and to an extent
just oop in general).
Find yourself a decent ruby book and have a browse through it (AWDR
has a quick bit about ruby as an appendix, but it’s just a quick
intro). There’s Programming Ruby (also known as the pickaxe), Ruby for
Rails, http://www.humblelittlerubybook.com/, etc…

Fred

Great ideas… but what I’ve found is that while I’m versed in oop in
general, (and in other languages), there seems to be this “wall” with
Rails. In that you know there must be a better way to do something,
so what is it and why? Do you just not trust your own coding style?

Do you know that there will be a view (but right now you are working
on the models) that will say “Give me all of the played
during this game” - so do you leave that answer up to the view, the
controller, or the model? Or another model?
games.find_by_id(201).played_cards. Do that in the controller?
controller_foo.get_played_cards? If you do it in the controller you
can ensure the current user is allowed to see that game, etc.

Questions like that only come up, I’ve found, with time and with
projects. Make stupid little rails projects to “prove out a concept”
and learn from your mistakes. If after a month of code, you find it
hard to access something and you keep repeating - then move that
something somewhere else. :slight_smile:

Yes, that’s basic OOP in general - but for some reason the new “rails
framework” idea that people come across, while not really new, makes
them rethink (and think they need to rethink) how they do things.

On Jun 6, 8:34 am, Frederick C. [email protected]

Carsten G. wrote:

This question sometimes arises: What if I need to do operation on
multiple data-models at a time?

The answer is not the Controller but: Create a class for handling the
two or more models (this is called a “Service-class”, and use this from
the Controller.

I forgot to mention, that there is an excellent example of this in
recipe 18 of “Advanced Rails Recipes” - do buy these books!!! :slight_smile:

  • Carsten

Frederick C. wrote:

On 6 Jun 2008, at 13:30, pepa007 wrote:

These aren’t really rails questions, they’re ruby (and to an extent
just oop in general).

Ii believe that the initial question about “what goes where in MVC” is
pretty much Rails-centric - Ruby is an OOP language, Rails is an MVC
framework.

First of all, I will recommend that you buy the two “Recipes” books:
“Rails Recipes” and “Advanced Rails Recipes”. They explain a lot of
“best practices” in Rails on specific problems, and through that also a
lot about what goes into the Model, Controller and View.

These are my rules-of-thumb - they go with the general concept of MVC:

Model

The model has all to do with storage of data, association between data,
etc.
These concepts always go into the Model:

  • Data-validaion before saving to database
  • ALL SQL-queries
  • Calculated fields based on selected data
  • Operation on data

This question sometimes arises: What if I need to do operation on
multiple data-models at a time?

The answer is not the Controller but: Create a class for handling the
two or more models (this is called a “Service-class”, and use this from
the Controller.

Controller

Everything that has to do with with HTTP requests and responses goes
into the Controller.
The controller is the only place, where you should handle “params”,
“session”, “cookie”, etc.
If you find yourself with a controller method, that spans more than 20
lines, then some of it probably belongs in the View or Model.

View

Explaining what the View should contain is probably best done by saying
what it should NOT contain :slight_smile:
NO programming logic whatsoever!
NO calls to a Model’s save/update methods! (though some people believe
that calling find-methods are ok for the View)

Display logic is ok. But if you start having a lot of “if” statements in
your view, you should probably create some helper methods.
Why is that? Well ideally YOU as a programmer shouldn’t create the View
code. A web-designer should do that. Make too complex ruby code inside,
and you are stuck with making all views yourself.

This list is by no means exhausted, but it should give you a broad
perspective of the principles. Hope it helps.

  • Carsten

On Jun 6, 2008, at 11:36 AM, Carsten G. wrote:

  • Calculated fields based on selected data

Controller

Everything that has to do with with HTTP requests and responses goes
into the Controller.
The controller is the only place, where you should handle “params”,
“session”, “cookie”, etc.
If you find yourself with a controller method, that spans more than 20
lines, then some of it probably belongs in the View or Model.

pepa007: ignore my discussion below – from what I can tell Carsten’s
rules are fairly generic in the Rails community, I’m raising more
“advanced” ideas, and likely ones the Rails view of the world doesn’t
agree with, or I’m wrong :slight_smile:

One of my struggles with Rails is this notion of skinny controllers
and fat models. I don’t buy it. At least, not as a “rule” – as a
more than likely guideline, I’ll agree it’s what you consider first
to see if it fits.

MVC in Rails seems to be treated like an exclusive 3-layer N-tier.
IMO MVC describes 3 roles for classes/objects. Every class you write
can generally be categorized as one of the three. That helps
determine the general shape and contents of that class, and the label
helps designers make decisions. Other than itself having internal N-
tier-ish layering (e.g. data connectors) Rails discussions seem to
ignore N-tier design in the applications.

MVC, IMO, does not dictate concepts like skinny controllers and fat
models and thus some of the rules stated above. I can see where this
comes from with a Rails controller pretty much intended specifically
for handling the final step of request-specific routing, but the
adoption of the notion that all other logic belongs in the model
doesn’t make sense to me. The domain-logic layer feels rather ignored
to me in Rails. Ignored, or maybe just oversimplified.

I have models (stripped down data structures) which I reuse with
different business logic. Sometimes, even different validation rules,
so not entirely fond of having validations attached to models either–
I prefer delegation for that role. Same for the business rules.
Separation of data & rules dictates that business logic lives outside
of the model.

Additionally, I have standardized user interfaces that abstract the
UI control to where models are pretty much just plugins to an overall
automated user input handling process (it’s like a super fancy
scaffolding). That process belongs neither in the model, nor in the
first level of a Rails controller’s method if we’re going to use that
just for HTTP handling–it is separate layer, but it is a controller
in an MVC world (or maybe it’s a abstracted model, but given where
Rails draws the lines between HTTP and persistence, the code belongs
in a Rails controller).

So, while for the majority of dead-simple web sites and simple web
applications that are straight forward hand-to-mouth request to data
handling, then I suppose these rules pretty much apply. But the idea
that once a controller method starts to get to be 20 lines something
probably belongs in the model–I don’t buy that at all. The code may
belong somewhere else, but to assume that it is always in the model
(as it would rarely likely belong in the view), I think is misleading
to sell it as an OOP rule of thumb.

Then again maybe all my code is junk, but I’ve had no problem
extending, maintining, and reusing it over many applications and
years – all of which I see as the real purpose of OOP/MVC. Maybe I’m
just over reacting to advice that’s good to give 99% of beginners,
but I find myself at odds with Rails design edicts from time to time,
and no way to really hash it out with someone to see if I’m wrong or
have a valid scenario that Rails didn’t consider / opted not to care
about.

– gw

On Jun 6, 2008, at 2:19 PM, Carsten G. wrote:

Greg W. wrote:

data-layer. The problem occurs when validation in one model is
depending on another
model.

In my past work I’ve leaned towards validating “input” rather than a
model. I had occasion to often reuse identical/nearly-identical data
storage but with some different validations and business rules. So, I
started to separate the two so that I could reuse a query ORM layer
and the data models, and place the validations and business rules in
a layer that preceded the data model in terms of where the real work
was done.

In effect where,
Rails is: model <-> controller,
my stuff was: (model<->domain) <-> controller

I got used to validating inputs before ever putting them into the
model. I don’t like Rail’s method of stuffing the model first, then
validating it–the h() on output rather than eliminating the
offensive data from the start. Bad data shouldn’t even get into the
model in memory IMO. So my validation system dealt with params as
data objects where the rules had the ability to be defined as
universal to all input sources, or specific to an input source.

This way when I build an application for “clubs” – data structures
like membership was generally very reusable with little or no change,
and the rules differences were handled separately.

Again, might not be “right,” but it’s what my reading and environment
lead me to do.

I think the “type” of applications I have built tend to have
different concerns that those that bore the development of Rails –
so that’s where I get most of my “hmmm, idunlikeit” reactions. Trying
to figure out how to mesh the two has been a challenge.

Maybe I’m
just over reacting to advice that’s good to give 99% of beginners,

My reply was exactly that - a beginners guide. :slight_smile:

Yeah, I know yours was, I was referring to the discussion & advice at
large. It’s all rather Steppford-ish in its uniformity–which is good
for the beginning programmer I suppose. The flip side is that it’s
difficult to find someone willing to talk outside the rails way. It’s
pretty much, “but… why would you do that? Rails says…”

I have also had my disagreements with Rails. Coming from the free
world
of C/C++, PHP and Perl, I am not used to the straight-jacket approach,
that Rails forces. But I’ve found myself programming faster in Rails
than in any other of the aforementioned languages - even from my first
Rails project - so I have reluctantly accepted that it is “The
Rails Way
or the Highway”. A price I now gladly pay for the power I get.

In my case, I had developed my own extensive framework starting in
2001 for these types of apps. Overall, I don’t find Rails any more
productive than my own framework. It has very similar coverage of
purpose and tools to Rails (some variations on what is built-in).
It’s also very convention over configuration oriented, though it’s
more open to variations than Rails is. So, I got used to 100% “my-
way” and I do find it a little hard to give up – not quite used to
this highway business yet :wink:

– gw

Greg W. wrote:

In effect where,
Rails is: model <-> controller,
my stuff was: (model<->domain) <-> controller

Actually I also miss more documentation about doing
model<->domain<->controller stuff in Rails.

You CAN do it, but it is IMHO one of the areas where Rails lack
conventions (which it otherwise has plenty of).

I got used to validating inputs before ever putting them into the
model. I don’t like Rail’s method of stuffing the model first, then
validating it–the h() on output rather than eliminating the
offensive data from the start. Bad data shouldn’t even get into the
model in memory IMO.

Rails does it like that because the model is responsible for “taking
care of itself”. It trusts nobody but itself to validate data before
saving it. But again, just because Rails does it, doesn’t make it the
only valid practice.

Not that I want to draw out the discussion (though I like your
arguments), but one of the good things I like about Rails’ “we only want
it done THIS way” is, that it makes it easier to enter an existing
project. Everything is in its “proper” way (at least proper from Rails
point of view). Coming from PHP (with its multitude of frameworks and
template engines) and Perl (with its famous “there is more than one way
to do it” quote), it’s actually a relief for me to be told of one way to
do things.

Then again, I’m 36. Maybe I’m getting too old for this sh*t… :slight_smile:

  • Carsten

Greg W. wrote:

On Jun 6, 2008, at 11:36 AM, Carsten G. wrote:

  • Calculated fields based on selected data

Controller

Everything that has to do with with HTTP requests and responses goes
into the Controller.
The controller is the only place, where you should handle “params”,
“session”, “cookie”, etc.
If you find yourself with a controller method, that spans more than 20
lines, then some of it probably belongs in the View or Model.

pepa007: ignore my discussion below – from what I can tell Carsten’s
rules are fairly generic in the Rails community, I’m raising more
“advanced” ideas, and likely ones the Rails view of the world doesn’t
agree with, or I’m wrong :slight_smile:

Ahh… I like a good discussion. :slight_smile: Well as long as your arguments are
good, your ideas don’t need to match those of everyone else.

One of my struggles with Rails is this notion of skinny controllers
and fat models. I don’t buy it. At least, not as a “rule” – as a
more than likely guideline, I’ll agree it’s what you consider first
to see if it fits.

I made an error in my description of the controller. I wrote:

The controller is the only place, where you should handle “params”,
“session”, “cookie”, etc.

But I did not mean, that this nessecarily is the ONLY things, that the
controller should handle.

The 20-lines “rule” should just be a gauge when you revise your code.
OOP idioms say that each method should be as simple as possible and not
fullfil more than one task. This also goes for methods in a controller.
Each method (action) should only handle one task - if you create too
many dependencies in a method, something is wrong with your design.

I don’t know yet, if I hold with the “skinny controller” idea, neither
with “each controller should just contain CRUD operations”. It might
impose too much constraint on your design and force you to invent
ressources that aren’t really there.

MVC, IMO, does not dictate concepts like skinny controllers and fat
models and thus some of the rules stated above. I can see where this
comes from with a Rails controller pretty much intended specifically
for handling the final step of request-specific routing, but the
adoption of the notion that all other logic belongs in the model
doesn’t make sense to me. The domain-logic layer feels rather ignored
to me in Rails. Ignored, or maybe just oversimplified.

I agree with you. The basic Rails introductions fail to discuss where to
put methods/code that interact with more than one datastructure at once.

Models are described as simply being classes on top of a database table.
So 3 tables => 3 model classes. With this scheme, people are tempted to
put domain-specific code into the controller, when they need to operate
on more than one table at a time.

I have models (stripped down data structures) which I reuse with
different business logic. Sometimes, even different validation rules,
so not entirely fond of having validations attached to models either–
I prefer delegation for that role. Same for the business rules.
Separation of data & rules dictates that business logic lives outside
of the model.

I don’t think, that business logic should live outside the model. A
model IMHO is responsible for validating data that it accepts into its
data-layer.

The problem occurs when validation in one model is depending on another
model.

So, while for the majority of dead-simple web sites and simple web
applications that are straight forward hand-to-mouth request to data
handling, then I suppose these rules pretty much apply. But the idea
that once a controller method starts to get to be 20 lines something
probably belongs in the model–I don’t buy that at all. The code may
belong somewhere else, but to assume that it is always in the model
(as it would rarely likely belong in the view), I think is misleading
to sell it as an OOP rule of thumb.

Again I agree. The code need not nessecarily be put into the model, but
most of the time it implies, that something is made unnessecarily
complex, and could be refactored out into “service” methods/classes.

Maybe I’m
just over reacting to advice that’s good to give 99% of beginners,

My reply was exactly that - a beginners guide. :slight_smile:

but I find myself at odds with Rails design edicts from time to time,

That is why they call it “oppionated software”. :wink:

I have also had my disagreements with Rails. Coming from the free world
of C/C++, PHP and Perl, I am not used to the straight-jacket approach,
that Rails forces. But I’ve found myself programming faster in Rails
than in any other of the aforementioned languages - even from my first
Rails project - so I have reluctantly accepted that it is “The Rails Way
or the Highway”. A price I now gladly pay for the power I get.

  • Carsten

On Jun 6, 2:30 pm, pepa007 [email protected] wrote:

  • which function/method goes where (M/C/helper), what is the rule to
    decide
  • how to call function from one to another (from M to C, between two
    Ms, between two Cs, available to all Ms, etc.) and how to pass
    parameters (when to use params[:whatever] and when the variable
    itself). when to use self.function etc.
  • in which case I need to pass @records/@record/records/record

Try this:

http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/19bad38ebfb1f1e7/04fae07685018046?hl=en&lnk=gst&q=model+view+controller+"Sheldon+Hearn"#04fae07685018046

Still works really well for me.

Ciao,
Sheldon.

On Jun 8, 2008, at 12:59 PM, Carsten G. wrote:

Greg W. wrote:

I got used to validating inputs before ever putting them into the
model. I don’t like Rail’s method of stuffing the model first, then
validating it

Rails does it like that because the model is responsible for “taking
care of itself”. It trusts nobody but itself to validate data before
saving it.

Not that I want to draw out the discussion (though I like your
arguments), but one of the good things I like about [the Rails Way]
is, that it makes it easier to enter an existing project…
Coming from PHP … and Perl …, it’s actually a relief
for me to be told of one way to do things.

Yeah, and I do admit, those are some of reasons I adopted Rails for
some current projects. I just have to keep reminding myself of that.

Others = Ruby’s promise–lacking now, but in 5 yrs it should be
great, and generally the permeation of agile and pragmatic principles
in the community. As much as I managed to accomplish on my own, I
simply wasn’t going to keep pace, and the Lasso language, as cool as
it is, simply wasn’t on the growth curve to attract enough high-end
talent to draw from to help out. That and a project with Thoughtworks
pushed me over the edge into giving Rails a go.

So, for now, it’s onward…

Then again, I’m 36. Maybe I’m getting too old for this sh*t… :slight_smile:

I’m 44, and this is my third career. I’ve monkeyed with programming
since 1982 (lots of work group apps from materials management to
bottling engineering processes), got more serious and generally web
focused since 2000, started OOP in 02, and 100% software and
independent in 2003. So that’s not a lot of time with OOP which is
why even though I found things that worked for me, I realize I have
much learning to do.

A lot of my coding has been to look at framework level issues–to use
some working projects as the cases for developing frameworks to use
in future projects. My target was to find that line that I now see as
the insanity of J2EE (too big for my types of apps), and the narrow
feld of vision of Rails. Rails is very close–I’d like just a little
more elbow room at times. I suspect after I get more familiar with
where and how to extend the framework, I’ll be able to add those
things I find important enough.

On top of that, I’ve spent my entire career researching, adapting,
and creating new technologies, new systems, new processes: from
designing and building complex industrial equipment for the big
semiconductor companies to managing corporate marketing for a $60M
company.

So at 44, I’m too old and too programmed to just accept someone
else’s way “just because” :slight_smile: It’s a blessing, and a curse.

– gw

Gentlemen,

Thanks so much for valuable tips!

Keep this discussion going, the only efficient way to shape best
practices is probably sharing and discussing them.

Sheldon H. wrote:

Try this:

http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/19bad38ebfb1f1e7/04fae07685018046?hl=en&lnk=gst&q=model+view+controller+"Sheldon+Hearn"#04fae07685018046

Still works really well for me.

Good points in that post.

Some things that I miss in Rails, though, are helpers. There is a helper
system for the views, but not for the controllers or for the models.
Both of these can use “helper-classes” defined in /lib, but I miss a
formalised way of doing this (since Rails is so oppinionated).

  • Carsten