Why Rails Controllers need a Double Render

{{{
In one of my last posts I “already discussed the improvements”:http://nicksda.apotomo.de/2010/10/10-points-how-cells-improves-your-rails-architecture/ Cells brings to your Rails app by *providing view components*.

The last day I had an lively discussion about the concept of _partials_ or page fragments in Rails.

*Partials make me feel sick.* People ordinarily use ’em in order to have “_DRY_ code”. However, usually the extensive usage of partials makes the architecture even worse.

* Partials blow up your controllers which should be _slim_ – partials _always_ blindly access variables sitting in the controller, which *increases controller complexity* and makes your code break often. _Just use a non-existent local and you’re knocked out_.
* Partials can’t be rendered in the controller. Unavoidably this *shifts code and knowledge to views* – isn’t that a so called “NO-GO”?
* Partials itself *can’t be tested* separately.

Today I’d like to show one concrete use-case how to *really DRY up your view code* with Cells.

h3. What’s nice about partials

In our discussion we were refering to *a form that was rendered in every action*. A Rails developer will put the form in a partial. This is _a good thing_.

*_UPDATE:_* The real form was way more complex! For educational purposes *I cut down this example* – I wouldn’t implement such an easy task with Cells, Lonny! 😉

Now we found out we need a customized button title in the form. We have two possibilities at this time.

* Save the *title in an instance variable* read by the partial.
* Pass the *title as a local* when rendering the partial.

The first is terrible. The second looked like this.

render :partial => "form", 
  :locals => {:title => "Create item."}

And in another view.

render :partial => "form", 
  :locals => {:title => "Update this item."}

The coached colleagues learning Rails asked: “_But… isn’t that the opposite of DRY?_” and I said “Yes.”.

h3. Can Helpers help?

We had several *identical calls in our views*. They started working out different approaches with helpers.

def my_form(title)
  render :partial => "form", #...

*Using helpers they were forced to use instance variables, again*, for transporting information _from controller to view to helper to partial_. It was a mess.

Suddenly, someone came up with a new idea: _”What if we call the helper in the controller?”_ – they tried, and failed. Every Rails developer has to *meet the @DoubleRenderError@ once in his life*.

I interrupted the experiment and introduced Cells getting wet.

h3. DRY up your views!

We simply put the view and associated code in a cell.

class FormCell < Cell::Base
  def display
    @title = opts[:title] or raise "No title passed!"
    render
  end
end

The state view reads the instance variable.

  = form_tag do # ...
  
    = submit_tag @title, :id => :btn

Using instance variables here is ok. Remember, we’re *in a small cell instance.* You don’t pollute a complete request controller with some rich _title_.

Even better, we got some options validation, too.

h3. Rendering twice in the controller

As we needed the form in every action, we *rendered it in a before_filter*. Yeah, Cells can be rendered just anywhere.

  class ItemController  "Create item", 
                :edit   => "Update this item"}

      @form_html = render_cell(:form, :display, 
        :title => titles[action_name])
    end

This is pretty DRY.

* We define titles and render the corresponding form *in one place*, as they do go together. We *don’t spread a bit code to every action*.
* The controller instance variable contains the rendered form markup.

Naturally, you’re not bound to filters – this is just a simple example.

h3. Testing the form

Being an agile TDD team we instantly travelled back in time and *wrote a test before implementing the cell*.

class FormCellTest  "Test your partials!"
    assert_select "form #btn", "Test your partials!"
  end

Having an *object-oriented partial* with backing functional test we decided to knock off work for today.

You can find the “Cells repo here”:http://github.com/apotonick/cells.
}}}

21 thoughts on “Why Rails Controllers need a Double Render

  1. I’m huge fan of cells but that approach doesn’t convince me. You focus on DRY but forget about MVC.
    1. What’s wrong with helpers approach? Why would you render a form itself in controller? It messes MVC up.
    2. If you really want render form in controller what about using render_to_string which prevents from DoubleRenderError
    3. Partials are testable easily with render_to_string approach

    I don’t want to defend partials. It’s pretty obvious they suck and doesn’t always follow DRY but for such an easy task isn’t using helper + partial pair keeping it simply stupid?

    All in all DRY, KISS and other principles are just buzzwords. Common sense is sometimes the best solution 🙂

    Like

  2. Render form in controllers complete no for me….I am of the strong type who never even creates a div element string in a variable then render it in the view though I have seen many do the same.

    Like

  3. As you know I’ve been using Cells all-in in a project, but I somehow went back to partials in my newer apps for now to minimize complexity. I noticed sometimes DRY and sweet architecture many times makes a simple app very complex. As I mentioned on IRC. I would probably use Cells for huge apps though I think.

    Btw, you should use the more fresh way of calling a partial to DRY it up a bit:

    render “form”, :title => “Create item.”

    I’ve personally started to put partials in “app/views/posts/partials/*” to make it easier to overview.

    Like

  4. In principle, I like the idea of Cells because they remove logic from views and remove the need for helpers. However, I’m not convinced that the benefits of Cells outweigh the complexity they add.

    My primary concern is that using Cells results in 2 additional abstraction layers (cells and cell views) while only removing the need for one existing abstraction layer (helpers).

    Without cells, you need to examine 3 layers to figure out a page’s content:
    * controller;
    * view;
    * helpers.

    With Cells, you need to examine 4 layers to figure out a page’s content:
    * controller;
    * cell;
    * cell view;
    * view.

    However, at the end of the day, everything I wrote above is moot, because I haven’t actually used Cells yet. So feel free to pick apart my argument and convince me to use Cells!

    Like

  5. @all: Thanks for your great and valuable comments so far! Cool!

    @Michał, @Łukasz, @grimen, @Nick and @Rohan: I took a stupid simple example to show how you could improve your architecture. Maybe the example was too simple? I think for such an easy task I wouldn’t use Cells myself!

    @Michał: #render_to_string in a helper is a good idea, I like that! Can you show me some example (maybe next time we drink), especially how you’d test that?

    However, I think rendering a form in the controller doesn’t fuck up MVC- you also render the “original” view in the controller, and a Cell is its own MVC-stack, so what’s wrong about that?

    @Rohan: Although I render the form in my controller I don’t touch rendering code at all, it’s encapsulated by the cell’s MVC stack. Is this generally wrong in your eyes?

    @grigio and @Łukasz: What does the term “sidebar” here refer to?

    @Nick: Cells are not meant to replace helpers! I use some helpers myself, but when it comes to rendering complex things I implement that with Cells.

    You’re absolutely right when you say cells increase the complexity as you have “more pieces of code to look at”. Anyway, the future of rich web apps is based on web components which split your monolithic controller/view into small widgets. So basically you have “small controllers” which all have the same concept and API, right?

    Thanks again guys, keep bashing my stuff 😎

    Like

  6. I have to agree with Nick Hoffman, and in fact I will go further: this concept is ridiculous. Not only are you abstracting view code out to a place where it simply doesn’t belong, thereby confusing issues that were formerly not confused, but you go even farther than that:

    In order to “solve” the problem of adding an instance variable or two (which is often actually not even necessary with partials… it depends on how irresponsibly you use them), you instead are passing AN ENTIRE PARTIAL’S WORTH OF DATA from the controller to the view, every time. What was once a mostly static bit of view code has now become, internally, nothing more than a giant honking variable that is getting passed around like a hot potato. If my impression of this is incorrect, then please explain statements like “We simply put the view and associated code in a cell…”

    In short, the “cure” here is far worse than the disease. Used properly, partials are quite DRY indeed. Instead, you are shooting an ant with a cannon, and forcing your code to lug around the cannon everywhere it goes. Bleh. I’ll pass. It is unnecessary abstraction and it does nothing to actually make code more efficient or DRY. Note that you are still passing the same variables… you are just doing it in a different place… a place that also breaks the MVC framework. If you like that place better, more power to you, but I think you are a nut.

    Like

  7. Don’t take that last statement too seriously, but let me explain: the problem here is that you are confusing MVC with the old “three-tier” architecture, in which your views were ideally completely dumb (mainly because they were often on a thin client), and all logic was in the “application” or business layer.

    But that is not the same as MVC. There is nothing in MVC per se that calls for your view logic to be completely dumb. On the contrary: your business logic is supposed to be confined as much as reasonably possible to your Model, and there is nothing wrong with putting View logic in your View. THAT’S WHAT THEY ARE FOR. And then your Controller ties them together.

    I, too, used to confuse MVC with three-tier. But that was years ago, when I was new to the MVC concept. I strongly suggest you get over it.

    Like

  8. By the way: you can’t use HAML and advocate for dumb, non-runtime-interpreted view code at the same time, without being a hypocrite.

    Like

  9. @Lonny: Gimme more, baby! It’s up to you to _abstract_ this stupid example to a more complex piece of code in your app. It is a simple, basic example of a dumb form.

    Nevertheless, every app has at least one or two spots where Cells help, without being a cannon. It’s not everyone’s cuppa to be able to abstract at all, though.

    Like

  10. @Lonny: I tell you what I think about MVC: I DO put code into views 🙂

    I never told anybody to have “non-runtime-interpreted views”. Where did you get that? Cells do use helpers themselves. All I want is: If your partial+helper mixtures get too complex, here’s something which could help you.

    Did you smoke the wrong pipe tonight or what’s wrong, dude?

    Like

  11. Lots of controversy here. That’s fun!

    @Nick Let’s say the example wasn’t the most accurate one. Anyway more posts like that 😉

    Cheers

    Like

  12. It strikes me that you asking for a new “smart” layer in between the controller and the templates.

    Basically you are looking at a situation where there is too much to place on the page. But within that volume there are still patterns, which should be brought out in a more explicit way than having partials referencing each other in an ad-hoc and non-documented way.

    Stephan

    Like

  13. @Lonny: I’ve had it with partials that can’t be tested, Rails “no double renders,” butt ugly calls to partials, and partials bloating my view directory that can’t be reused easily because I don’t know which controller will use them. Bleh.
    Cells (and it’s brilliant cousin Apotomo) make my life easier, I don’t have to pollute config.rb or my controllers with AJAX request handlers, all my cells are organized in a separate directory, and they are all TESTABLE in isolation. So far, I’m very happy with this library.
    That internally we’re carrying around a string variable is not an issue with me. That’s in code that is tested (Cells has an extensive test suite, another win for me) and besides, have you looked under the Rails hood? There’s more to be worried about there, not whether or not a string variable is being used appropriately to ease our development work and help us create quality apps.

    Like

  14. @Kevin Triplett, have you taken a look at Erector? It’s a lib that lets you do views in an OO manner, complete with methods. It’s basically a substitute for ERB, a complete one.

    Generally, it seems that Cells is abstracting only one piece of the MVC problem and as such it may make the architecture harder to comprehend. Like Nick Hoffman said, take it with a grain of salt, as I haven’t had the chance to use Cells in anger just yet.

    However, I do take issue with one thing the OP said.

    “@Michał, @Łukasz, @grimen, @Nick and @Rohan: I took a stupid simple example to show how you could improve your architecture. Maybe the example was too simple? I think for such an easy task I wouldn’t use Cells myself!”

    Are you saying here that you’d mix Cells in intermittently? As in, if you have “simple” views, you’d use the regular Rails way of doing forms, but if the view/controller is gets more complex (also need to define that, IMO), you’d use Cells? Wouldn’t this make the codebase a lot harder to maintain? Shouldn’t one be consistent in the usage of libraries during the course of a project?

    Like

  15. @Srdjan: Right now, I do use Cells only for more complex view components – if I would be in the position to decide about Rails’ architecture I wouldn’t do differentation between “views” and “partials”, and a controller would basically be a “main” cell calling “smaller” cells.

    This reduces the Rails codebase (no separate view and partial code) and the misunderstandings (What is a view? What is a partial? What is a Cell?).

    BTW – in Cells, we already do that, we don’t distinguish between two view types, we just got views.

    If you use Cells only partly, what’s the problem with it? You can introduce it step-by-step, write strong tests and thus improve your app. Isn’t that great? 😀

    Like

  16. I don’t see the point of cells. I don’t think its that difficult to pass variables to partials or to write test code for your helpers.

    If partials are are cluttering your views than you need to learn to better refactor into helpers. If you don’t know how to write test code for helpers than thats your problem.

    Like

  17. @Andrew: Partials as it are not the problem, dude, calling the partials with all the knowledge concentrated in one monolithic controller is my problem.

    I guess I will stop answering these ignorant comments now! Go on, use your shitty partial+helper work-arounds and simply ignore the fact that the current Rails view layer is far away from MVC. Bye bye, Andrew!

    — UPDATE —
    Haha, you tell me that I’m too stupid to handle my partials but at the same time you host a blog post about the usage of binding in a helper to magically pass arguments to your partial?

    — UPDATE —
    Andrew, excuse me, I’m too rude. Just give it a try 😉

    Like

Leave a comment