Best practices for conditional display in views?

Hi.

I am writing an application that has a lot of boolean conditional
display logic, like this:

<% if user.description then %>

<%= user.description %>

<% end %>

Often the displayed content is more complex than the above, and to clean
up my views I am trying to pull a lot of this sort of thing into
partials.

However, the problem arises that I will frequently need to format the
same information in different ways. For example, the above user
description appears as a standalone item so it can logically be wrapped
in a

tag. But it might be an inline item that should appear in a
, or a list item that should appear in

  • tags.
  • That means that the enclosing tag (and, typically, CSS class reference)
    need to be pulled back out into the view, like:

  • <%= render :partial => "user_description" %>
  • But this will result in empty

    or or

  • tags being rendered
    in the event that the conditional test (in the partial) returns false,
    which happens frequently. So that suggests I should put the conditional
    logic back in the view and remove it from the partial altogether:
  • <% if user.description then %>

    <%= render :partial => "user_description" %>

    <% end %>

    …which sort of defeats the purpose of the partial.

    Is there any recognized best practice for handling this situation? What
    would be handy is if the render method could take an :if parameter. Or I
    suppose I could write a helper that forms a wrapper tag given a tag name
    and class, and include the helper in lots of partials:

    <%= render :partial => “user_description”, :locals => { :tag_name => li,
    :class => “css_class” %>

    But I’m open to better suggestions.

    Thanks!

    /afb

    Hi –

    On Sun, 17 Dec 2006, Adam B. wrote:

    Often the displayed content is more complex than the above, and to clean
    need to be pulled back out into the view, like:
    <% if user.description then %>
    and class, and include the helper in lots of partials:

    <%= render :partial => “user_description”, :locals => { :tag_name => li,
    :class => “css_class” %>

    But I’m open to better suggestions.

    I tend to do the second-to-last way you’ve shown. The last way, with
    locals, is less appealing to me, as it has the same information but in
    a somewhat overly abstracted form. I don’t think putting the partial
    in an HTML element defeats the purpose. Basically the purpose is
    partly to un-spaghettify the view, and partly to reuse stretches of
    template – and doing it that way, you do both.

    David


    Q. What’s a good holiday present for the serious Rails developer?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    aka The Ruby book for Rails developers!
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)

    I don’t think putting the partial
    in an HTML element defeats the purpose. Basically the purpose is
    partly to un-spaghettify the view, and partly to reuse stretches of
    template – and doing it that way, you do both.

    David, I’m sure you’re right. It just somehow seems wrong to have the
    same conditional logic show up again and again. I can abstract the
    content into a partial, but the logic hangs around in the view, which to
    my eye is still overly pasta. I’ll keep thinking about it.

    It does occur to me that part of the messiness arises because of the
    need to close the bounding HTML tag. A helper that could write,
    conditionally, an HTML tag around a partial (or anything else) would be
    kind of useful. It might look similar to how folks commonly combine
    link_to and image_tag, i.e.:

    <%= tag :p, :class => “css_class”, :wrap => render_to_string(:partial =>
    “user_description”), :if => user.description %>

    Thanks for your time.

    /afb

    Another way may be to pass a variable into the partial, then render
    appropriately:

    <%= render :partial => “user_description”, :wrap_in=> “p” %>
    <%= render :partial => “user_description”, :wrap_in=> “li” %>
    <%= render :partial => “user_description”, :wrap_in=> “span”, :class =>
    “my_class” %>

    _user_description
    <% if user.description then %>
    <<%= params[:format] %> class="<%= params[:class] %>">
    <%= user.description %>
    </<%= params[:format] %>>
    <% end %>

    This would be better suited to an application helper and could do with
    some error checking.

    On Dec 18, 12:46 pm, Adam B. [email protected]

    Sorry - ignore that params stuff - wrong part of MVC, but you get the
    idea…

    OK, ok, ok I need sleep:

    <%= render :partial => “user_description”, :locals => {:wrap_in=> “p”}
    %>
    <%= render :partial => “user_description”, :locals => {:wrap_in=>
    “li”} %>
    <%= render :partial => “user_description”, :locals => {:wrap_in=>
    “span”, :class =>
    “my_class”} %>

    _user_description
    <% if user.description then %>
    <<%= wrap_in %> class="<%= class %>">
    <%= user.description %>
    </<%= wrap_in %>>
    <% end %>

    A bit uglier than the first attempt (which required rewriting of the
    render method), but it works.

    /me gone to get coffee

    Hi –

    On Sun, 17 Dec 2006, askegg wrote:

    _user_description
    <% if user.description then %>
    <<%= wrap_in %> class="<%= class %>">
    <%= user.description %>
    </<%= wrap_in %>>
    <% end %>

    A bit uglier than the first attempt (which required rewriting of the
    render method), but it works.

    I’m trying to put my finger on why I don’t like pushing the
    conditional stuff out to the partial. Maybe it’s that I always feel a
    little queasy/guilty about putting conditionals in the views, rather
    than the controller, so putting them in the partials feels even less
    “pure” :slight_smile: Mind you, I do put conditionals in views (I’m not a
    purist on that, if purism means not doing so), though if there’s so
    much conditional logic that it starts to bother me, I usually see that
    as a sign that I should really have more than one template.

    David


    Q. What’s a good holiday present for the serious Rails developer?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    aka The Ruby book for Rails developers!
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)

    Maybe it’s that I always feel a
    little queasy/guilty about putting conditionals in the views, rather
    than the controller, so putting them in the partials feels even less
    “pure” :slight_smile:

    That makes sense to me in general. In this case I’m talking about such
    small nuggets of information that I guess I have a stronger stomach. :slight_smile:
    And really the conditional logic is almost always of the sort “if this
    thing exists then style and show it”, so the logic is closely coupled
    with the actual display.

    There just seem to be many cases where you want to show some optional
    nugget but not have the appearance of the template go all ahoo if said
    nugget isn’t available for some reason…

    Thanks again for your input.

    /afb

    Hi all,

    2006/12/17, askegg [email protected]:

    OK, ok, ok I need sleep:

    <%= render :partial => “user_description”, :locals => {:wrap_in=> “p”}
    %>
    <%= render :partial => “user_description”, :locals => {:wrap_in=>
    “li”} %>
    <%= render :partial => “user_description”, :locals => {:wrap_in=>
    “span”, :class =>
    “my_class”} %>

    <%= tag :p, :class => “css_class”, :wrap => render_to_string(:partial =>
    “user_description”), :if => user.description %>

    I would go with view helpers, such as this:

    app/helpers/application_helper.rb

    def wrap(tag, tag_options, *partial_args)
    content_tag(tag, render(*partial_args), tag_options)
    end

    app/views/bla/bla.rhtml

    <%= wrap(:p, {:class => ‘a’}, :partial => ‘user_description’) if
    @user.description %>

    app/views/shared/_user_description.rhtml

    <%= user.description %>

    Even your _user_description partial should probably be extracted to a
    view helper. And having many of those will show you you really need
    some other kind of view helper: one that’s generic and is specific to
    your domain.

    Hope that helps !

    François Beausoleil
    http://blog.teksol.info/
    http://piston.rubyforge.org/

    Do you really need a hash-based
    interface to the HTML, rather than the HTML itself? I’m interested in
    what the advantages would be.

    You’re probably right. It’s likely just a question of style.

    However, I was browsing through the API and discovered that what I and
    others described above already exists in the form of “content_tag”. You
    can say:

    <%= content_tag(“p”, render_to_string(:partial => “user_description”),
    :class => “css_class”) if user.description %>

    or even:

    <%= user.description ? content_tag(“p”, render_to_string(:partial =>
    “user_description”), :class => “css_class”) : content_tag(“p”, " ")
    %>

    Which isn’t too bad if you like that sort of thing. In other words, if
    you happen to be a Perl programmer. :slight_smile:

    /afb

    This kinda looks like the way I usually do it:

    <%= “

    #{user.description}

    ” if user.description %>

    Which I think is readable enough

    Adam wrote:

    Do you really need a hash-based
    interface to the HTML, rather than the HTML itself? I’m interested in
    what the advantages would be.

    You’re probably right. It’s likely just a question of style.

    However, I was browsing through the API and discovered that what I and
    others described above already exists in the form of “content_tag”. You
    can say:

    <%= content_tag(“p”, render_to_string(:partial => “user_description”),
    :class => “css_class”) if user.description %>

    or even:

    <%= user.description ? content_tag(“p”, render_to_string(:partial =>
    “user_description”), :class => “css_class”) : content_tag(“p”, " ")
    %>

    Which isn’t too bad if you like that sort of thing. In other words, if
    you happen to be a Perl programmer. :slight_smile:

    /afb

    Christian J. wrote:

    This kinda looks like the way I usually do it:

    <%= “

    #{user.description}

    ” if user.description %>

    Which I think is readable enough

    Yes, it’s much more readable than mine. I have an irrational fear of
    HTML in strings inside RHTML tags, but that’s between me and my
    therapist.

    /adam

    Hi –

    On Mon, 18 Dec 2006, Francois B. wrote:

    “span”, :class =>
    end
    some other kind of view helper: one that’s generic and is specific to
    your domain.

    I’d tend to keep the partial as a partial, not a helper. In fact
    usually I end up turning helpers into partials, more than the other
    way around.

    I don’t know… all of this seems like a lot to go through to avoid
    having

    or

  • in the view. Do you really need a hash-based
    interface to the HTML, rather than the HTML itself? I’m interested in
    what the advantages would be.

    David


    Q. What’s a good holiday present for the serious Rails developer?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    aka The Ruby book for Rails developers!
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)