Teaching Models to Render Themselves in the Controller

I am trying to teach my models how to render themselves, i.e.

<%= my_model_object.render() %>

Let me explain my reasoning and proposed method before this gets shot
down as anti-MVC.

Let’s say I am writing a contact-management application. I have a
class Contact. I will need to display this class all over the
application. My first choice is to use a partial.

Now I can render my Contact with:

<% render_partial ‘contact_view’, :contact => my_contact %>

However, I start doing some ajax things, where I need to render a
contact and return it with an AJAX call. So, I simply render the
partial from my controller. Not too bad, as long as I can keep
straight what partial to call and what locals I need to pass where.
However, to make things a little easier on myself, I can create a
helper method in the controller like this:

helper_method :render_contact
def render_contact(contact)
render_partial(‘contact_view’, :contact => my_contact)
end

I can now call this same function from my view to render the page
initially, and from my controller to render new contacts for AJAX calls.

The next step is where I’ve run into trouble. Instead of having all
of these methods in the controller and calling out to them whenever I
need a Contact rendered, how about sticking the methods right onto
the model itself? Of course this breaks MVC if I put it on the model
in the contact.rb file, the contact is no longer reusable in other
places. But with ruby I’m supposed to be able to dynamically extend
objects. So why not extend my contact in my controller, teaching it
to render itself? In this way, different controllers could have
different rendering code for a Contact, and the Contact class itself
is never altered, but the code on my page goes from:

<%= render_contact contact %>

to

<%= contact.render() %>

and the controller AJAX code is likewise simplified.

So that’s the what and why, but for the life of me, I cannot figure
out the how. I am fairly new to ruby, and I think I’m supposed to be
able to do something like

def Contact
def render()
# render code goes here
end
end

inside of the controller, but I cannot for the life of me to get it
to work. If anyone call tell me how to do something like this, or if
there’s some alternative method that’s just as clean, I’m all ears.

Sorry for the longwinded message, but I felt that I should try to
explain myself as clearly as possibly with something that looks on
the surface to be a blatant breach of MVC.

In case I haven’t been clear, or maybe just because it’s in my head
and it’s late, here’s a metaphor I came up with:

Imagine paratroopers getting ready to jump out of a plane. As they
file towards the front of the plane, the officer hands them a
parachute, which they then put on and jump out. On the way down they
pull their own cord and parachute to safety. This is what I am trying
to do, with the model objects being the soldiers, the officer being
the controller, and the sky being the view. The method which I am
trying to avoid is that of pushing the soldiers out of the plane, and
then sending a parachute down after them.

Thanks for even reading this far, if you have,

Ozzi

On Tue, Feb 14, 2006 at 01:59:10AM -0600, Nathan R. wrote:
} I am trying to teach my models how to render themselves, i.e.
}
} <%= my_model_object.render() %>
}
} Let me explain my reasoning and proposed method before this gets shot
} down as anti-MVC.
[…]

Having a model render itself would be anti-MVC in most languages, but…

} The next step is where I’ve run into trouble. Instead of having all
} of these methods in the controller and calling out to them whenever I
} need a Contact rendered, how about sticking the methods right onto
} the model itself? Of course this breaks MVC if I put it on the model
} in the contact.rb file, the contact is no longer reusable in other
} places. But with ruby I’m supposed to be able to dynamically extend
} objects. So why not extend my contact in my controller, teaching it
} to render itself? In this way, different controllers could have
} different rendering code for a Contact, and the Contact class itself
} is never altered, but the code on my page goes from:
[…]

…you’re on the right track.

} So that’s the what and why, but for the life of me, I cannot figure
} out the how. I am fairly new to ruby, and I think I’m supposed to be
} able to do something like
}
} def Contact
} def render()
} # render code goes here
} end
} end
}
} inside of the controller, but I cannot for the life of me to get it
} to work. If anyone call tell me how to do something like this, or if
} there’s some alternative method that’s just as clean, I’m all ears.
[…]

I’d say you should put them in your helper files, rather than your
controller files. The helper files are part of the view layer.

} Thanks for even reading this far, if you have,
} Ozzi
–Greg

There’s nothing stopping you from doing this currently. All objects in
ruby are open for modifacations, even instances of objects, not just
the class definitions. You can add a method to one instance of an
object and only that object will have it,

-Nick

On Tue, 14 Feb 2006 08:31:08 -0500, Gregory S. wrote:

I’d say you should put them in your helper files, rather than your
controller files. The helper files are part of the view layer.

Maybe the OP is saying something I was thinking last night - it’d be
nice
if helpers could provide methods to a model, so that you COULD create a
helper for contact.render() instead of render_contact(contact). Just
some
syntactic sugar.

Jay L.

On Tue, Feb 14, 2006 at 11:40:40AM -0500, Jay L. wrote:
} On Tue, 14 Feb 2006 08:31:08 -0500, Gregory S. wrote:
}
} > I’d say you should put them in your helper files, rather than your
} > controller files. The helper files are part of the view layer.
}
} Maybe the OP is saying something I was thinking last night - it’d be
nice
} if helpers could provide methods to a model, so that you COULD create
a
} helper for contact.render() instead of render_contact(contact). Just
some
} syntactic sugar.

It certainly can. Suppose you have controllers/foo_controller.rb,
helpers/foo_helper.rb, and models/foo.rb in your app directory. You
don’t
want to put the render method in the models/foo.rb or
controllers/foo_controller.rb files because it belongs in the view
rather
than the model or controller, respectively. But if you put it in the
FooHelper module in the helpers/foo_helper.rb then it winds up in the
foo_controller class, and that’s not what you want either. Instead, your
helpers/foo_helper.rb file looks like this:

module FooHelper
end

class Foo
def render
#…
end
end

When you are in views/foo/*.rhtml the helpers/foo_helper.rb file has
clearly been loaded, right? So the Foo class (i.e. the model) will have
the
render method added to it. I’m not 100% certain of whether you need to
specify the ActiveRecord::Base subclass in the helper file, but I
suspect
not. You may also want to add a require “foo” or “models/foo” or
whatever
to make sure the model has already been loaded. Play with it and see.
Let
me know how it turns out.

} Jay L.
–Greg

Tom, I enjoy your posts a lot, but I have to respectfully disagree
here… I think adding
behavior to the object to which it belongs is always the better choice
over starting a
never-ending case statement.

I hope Ozzi will try the model-extending approach that Greg suggested
and let us know how
it goes!

b

On Feb 14, 2006, at 8:40 AM, Jay L. wrote:

Just some
syntactic sugar.

Why not make a dispatcher method in helper, render() that cases object
type, and either executes the valid code directly or as part of a
specific
render helper for the object type?

def show(object)
case object.class
when User
# render code for User
# or show_user(object)
when Blah
# render code for Blah
# or show_blah(object)
else
raise :YourVoiceStridently
end
end

Then it’s just a syntax issue:

contact.render

-vs-

show contact


– Tom M.

On Feb 14, 2006, at 9:47 AM, Ben M. wrote:

Tom, I enjoy your posts a lot, but I have to respectfully disagree
here… I think adding behavior to the object to which it belongs
is always the better choice over starting a never-ending case
statement.

I hope Ozzi will try the model-extending approach that Greg
suggested and let us know how it goes!

Hey, I largely agree with you Ben, so don’t sweat the disagreement!

It’s like the choosing the worst of two evils. :frowning:

If the case just distributes to helper methods, then it’s not such an
ugly thing…

P.S. I think Greg’s extension was to be handled in application.rb. If
that’s the case, I just ran into
an issue with such things, in that those modifications WILL NOT
be available to the models when
firing up a console, and unit tests likely won’t be able to hit
them either.


– Tom M.

On Tue, Feb 14, 2006 at 11:18:29AM -0800, Tom M. wrote: […]
} P.S. I think Greg’s extension was to be handled in application.rb. If
} that’s the case, I just ran into an issue with such things, in that
those
} modifications WILL NOT be available to the models when firing up a
} console, and unit tests likely won’t be able to hit them either.

I was suggesting putting them in helpers/_helper.rb,
actually.
I’m not sure how that affects the console or unit tests, but the point
is
to make the methods available in views and nowhere else.

Now that Rails 1.0 is out and solid, it might be time to start thinking
about what should go into 1.1 (or 2.0). I’d suggest that the directories
under app should be split up more. The helpers directory should be
renamed
something clearer (controller_render_helpers, or something more concise)
and
that there should be another directory of “helpers” for models, which
would
suit this need perfectly.

Okay, I’m on a roll now. Consider the following directory structure
within
app:

controllers
controllers/render
models
models/validation
models/render
views
views/layouts

The models/render, controllers/render, and models/validation directories
contain modules which are automatically included in the associated model
or
controller as appropriate for the context. The controllers/render
directory
is essentially identical to the existing helpers directory.

Of course, this may not make sense. Please comment.

} – Tom M.
–Greg

On 2/14/06, Nathan R. [email protected] wrote:

Imagine paratroopers getting ready to jump out of a plane. As they

file towards the front of the plane, the officer hands them a
parachute, which they then put on and jump out. On the way down they
pull their own cord and parachute to safety. This is what I am trying
to do, with the model objects being the soldiers, the officer being
the controller, and the sky being the view. The method which I am
trying to avoid is that of pushing the soldiers out of the plane, and
then sending a parachute down after them.

This is a good metaphor but MVC webapps is nothing like parachuting :slight_smile:

Tony

First of all, thanks for all the replies. Sorry I haven’t been able
to get back until now.

Greg, I like your idea, I think it’ll work great. Unfortunately,
being the newbie I am, I’ve run into a problem I haven’t quite
figured a way around.

First of all my helper class (foo.rb):

class Foo < Foo.superclass
def render
“Test.”
end
end

This seems to work great – I can call the method in my view for
normal page rendering, and in my controller for AJAX rendering.

(I needed to add the “< Foo.superclass” because i was getting a
parent class mismatch or some such. “< ActiveRecord::Base” would work
the same, I just think this is cleaner.)

However, if I try to do:

class Foo < Foo.superclass
def render
render_partial ‘foo_partial’
end
end

I get a method not found error. Of course this makes sense, but what
is the cleanest way of including the render_partial method there? I
suspect it has something to do with blocks or closures. Could I
somehow define the render() method inside the helper method where
render_partial is available and then attach it back to the class? Or
is there a simpler way?

Like I said, I’m new at ruby, and I’m coming off doing mostly java,
so I’m not really sure about how some of these things work. I
appreciate all of the help though, thanks :slight_smile:

Ozzi

Tony C. wrote:

On 2/14/06, Nathan R. [email protected] wrote:

Imagine paratroopers getting ready to jump out of a plane. As they

file towards the front of the plane, the officer hands them a
parachute, which they then put on and jump out. On the way down they
pull their own cord and parachute to safety. This is what I am trying
to do, with the model objects being the soldiers, the officer being
the controller, and the sky being the view. The method which I am
trying to avoid is that of pushing the soldiers out of the plane, and
then sending a parachute down after them.

This is a good metaphor but MVC webapps is nothing like parachuting :slight_smile:

Tony

I think the metaphor might work with some tweaking. Let’s say that
rather than the officer, the pilot is the controller. How MVC works is
this: The pilot calls back to the soldiers and tells them to jump, then

  • without checking to see if they’ve left the plane - he flys in a loop
    back around to where he thinks they will be falling, and throws open
    parachutes out of the plane to catch them.

:slight_smile:

On Tue, Feb 14, 2006 at 04:00:06PM -0600, Nathan R. wrote:
[…]
} First of all my helper class (foo.rb):
}
} class Foo < Foo.superclass
} def render
} “Test.”
} end
} end
}
} This seems to work great – I can call the method in my view for
} normal page rendering, and in my controller for AJAX rendering.
}
} (I needed to add the “< Foo.superclass” because i was getting a
} parent class mismatch or some such. “< ActiveRecord::Base” would work
} the same, I just think this is cleaner.)

Excellent! I thought it would work and I’m glad it did. Also, I like the
elegance of using Foo.superclass.

} However, if I try to do:
}
} class Foo < Foo.superclass
} def render
} render_partial ‘foo_partial’
} end
} end
}
} I get a method not found error. Of course this makes sense, but what
} is the cleanest way of including the render_partial method there? I
} suspect it has something to do with blocks or closures. Could I
} somehow define the render() method inside the helper method where
} render_partial is available and then attach it back to the class? Or
} is there a simpler way?
[…]

Well, render_partial is a method of the ActionController::Base class
(i.e.
the base class of all controllers). What you might try doing is making
render take an argument, and calling render with self, e.g.:

<%= @foo.render(self) %>

…and define render as:

class Foo < Foo.superclass
def render(controller)
controller.render_partial ‘foo_partial’
end
end

No guarantees that this will work, but it’s worth a try.

} Ozzi
–Greg

On Tuesday, February 14, 2006, at 4:00 PM, Nathan R. wrote:

class Foo < Foo.superclass
def render
render_partial ‘foo_partial’
end
end

Try

def render
render :partial=>‘foo_partial’
end

make sure you name the file ‘_foo_partial’

_Kevin

I’ll try that, unfortunately I think it kind of defeats the elegance
I’m going for in the page, i.e. <=% foo.render() %> as opposed to <%
foo.render(@controller) %> or whatever it would work out to.

I won’t get a chance to play with it until tomorrow sometime, so
maybe I can build off of that into something more elegant. But if
anyone has any ideas, please, keep them coming. As always, thanks for
the help. I’ll let you know what I come up with when I get a chance
to play with it.

def render(controller)
controller.render_partial ‘foo_partial’
end
end

No dice. First of all, render_partial is a protected method. Trying
to get around that, I made a public method in the controller that
would call the partial, but then I get an error to the effect of only
one render being allowed at a time. So at this point I really seems
stuck to doing all of my render calls from the controller or helper.

This still leaves me with my base problem, and maybe there’s an
easier answer. I want to be able to call the same method in the view
and the controller to render a block of HTML. In the view I need it
for initial page rendering, and in the controller I need it for AJAX
calls. The only way I have found to do this is by defining my method
in the controller and using “:helper_method” to export it to the
view. It works, but it just seems messy/wrong. I would rather put the
code in the helper, but there doesn’t seem to be a way to call it
from the controller. Tacking the code onto the model seemed like a
good way to go, but I don’t seem to be able to figure out a way to do
that either.

So for now I’m going to stick with putting my methods in the
controller and exporting them with “:helper_method”, but if someone
came up with a cleaner way I would definitely like to hear it.

Thanks everyone for the help,

Ozzi

Tony C. wrote:

the controller, and the sky being the view. The method which I am
trying to avoid is that of pushing the soldiers out of the plane, and
then sending a parachute down after them.

This is a good metaphor but MVC webapps is nothing like parachuting :slight_smile:

This suggests wrapping the model with a renderer which has an
appropriate to_s implementation, and giving the wrapper to the view.

regards

Justin

On 2/18/06, Justin F. [email protected] wrote:

Tony C. wrote:

This is a good metaphor but MVC webapps is nothing like parachuting :slight_smile:

This suggests wrapping the model with a renderer which has an
appropriate to_s implementation, and giving the wrapper to the view.

Which brings up the question, is #to_s the appropriate place for
something to convert itself to HTML? Perhaps #to_html would be more
correct.

Tony

I’m not sure I see what problem you are having here.

Firstly, a model should know nothing about rendering. It is not a models
responsibility to render itself. Rendering belongs in the view, even if
you
use renderer classes to render your models. This is all about good
design
and loose coupling.

If you want to render something in a normal view and in response to an
AJAX
call, have you considered upgrading to Edge Rails and using RJS
templates?
They would seem like the perfect solution.

Cheer
Luke R.

Tony C. wrote:

Which brings up the question, is #to_s the appropriate place for
something to convert itself to HTML? Perhaps #to_html would be more
correct.

The only problem there is what if you need different html
representations of the same
model object… like a “view” representation vs. an “edit”
representation?

Another idea – something I’ve toyed with in Java – is to “domify” the
model object. I
noticed there’s an xml-mapping gem that maps Ruby objects to xml and
back. So, you map the
object to xml, and then use a variety of xslt’s to create the various
html representations
you want.

The hard part there looks like doing the xslt’s… there don’t appear to
be any xslt gems
and the only other xslt for ruby I could find is distributed as c source
code. :frowning:

b