Once upon a time, there was a thing called "Rails Components." They were heavyweight and nobody used them, so the powers that be took the axe to them. They live no more.
That said, there is a real need for a lightweight component system in MVC frameworks. Something that:
- works like Rails partials, in that you can reuse common, existing code
- use existing controller variables like params and session to do different things on the basis of what's happening in the current request
- most importantly, not force you to give up the C in MVC simply because you want to reuse some code outside of a single controller
Merb parts are the simple answer to that problem. First of all, Merb parts work just like Merb controllers; you get a new filter stack, layouts (if needed), and the full gamut of render functions that you have in normal Merb controllers. You also get to share all of the regular controller variables (request, params, cookies, headers, session, response). And because Merb's philosophy is to have actions return strings, you can use the render methods, or any other string manipulation in your action, without fear of running into a "double-render" issue.
Here's a simple example:
class Foo < Application def foo render end end class Bar < Merb::PartController before :foo def foo @x = 1 end def baz render end end app/views/foo/foo.erb <%= part Bar => :baz %> app/parts/views/bar/baz.erb <%= params[:hello] %> <%= @x %>
In the example above, the view in the controller proper calls out to the part. The part runs just like a regular controller, so it has a before filter, which sets the
@x instance variable to 1. It then calls the baz method, which renders its action. In the action, you'll have access to the params from the original controller. You'll probably want to handle that stuff in the part controller, but this just demonstrates that it percolates all the way down.
Because parts reuse the existing controller stuff, they're very fast, and not the red-headed stepchild of controllers. Just like mailers, we benefit from the existence of AbstractController, which gives us the full filter stack, the ability to throw to stop the filter (and return an associated string as the result of the part), and all the other niceties of controllers.
Good stuff, huh? I have some more things to post about Merb, but soon... a comprehensive example!