[Feature request] content_tag do |el| ... end to create complex tags

Hello everyone,

I have a feature request here that comes from an internal struggle here between view helpers, decorator patterns and ERB in general. A problem that occurs from time to time is how to build HTML tags with different settings depending on the some states. Here’s an example of what I mean.

<% for @posts.each do |post|%>
<%= content_tag :li, post.title, class: “post #{post.id == 3 ? ‘selected’ : ‘’}” %>
<% end %>


With builtin’ methods, there’s many way to build this kind of HTML tag. And I’m sure people here knows a few of them. However, none seem to really make it easy to build them. So I decided to take a stab at it this weekend and came up with this solution.

<% for @posts.each do |post|%>
<%= content_tag :li, class: %w(post) do |li| %>

<% if post.id == 3 %>

 <% li.css << 'selected' %>

<% end %>


<% end %>
<% end %>

All attributes can be either set inline (as previously possible) or through a tag object that is available inside the block. Now, since this might not be really easy to figure out how useful this could be, I created a helper that overrides content_tag() and saved it as a gist for you to test out locally. It’s very possible that there’s a few bugs as it’s the very first version.

Gist: https://gist.github.com/pothibo/69d60505fa6e44863e52

Would this be something RoR:Core would be interested in merging into Rails?


How about moving the conditional to a helper in your first example? Just curious to know if you would prefer that approach.



:-1: You should be using helpers.

<% for @posts.each do |post|%>
<%= content_tag :li, post.title, class: post_classes(post) %>

<% end %>

in PostHelper

def post_classes(post)

your code here


I am aware of the existence of helpers. But they are in no way a silver bullet to building HTML tags. First of all, the number of helper_class() methods proportionally increment with the number of attributes/class you use. Soon enough, you get very complicated helper method name due to very close but yet different methods. This is one of the reason why some people uses Presenters/Decorators in their project.


to me this solution doesn’t look cleaner, nicer, shorter than the example using inline test. I would use helpers to do this kind of things.

Helpers are testable!
Views should have no complex logic on them.

This is as testable as any helpers. This argument is moot.

Could you give an example how to test it before burying my argument.

Also helpers can be reused in other views/partials .

This is actually my point. Helpers are useful when you build a method that is reusable enough to be used in different places. I didn’t write this because I wanted to get rid of helpers. I still use helpers while using this new content_tag() method.

My rule of thumbs is as follow:

I start with content_tag, as soon as I can use a helper to wrap different content_tag under 1 helper method, I’ll do it.

I believe that there’s a space between inline HTML and helper methods that this could very well address. As for the tests, well, I don’t know how you tests your helpers but I do test mine by looking at the rendered HTML and querying it. Same can be done with this method. I highly doubt that you don’t have a single flow condition in your views.

I want to set aside the arguments on whether this would encourage less clean code or move Rails in good direction.

I can imagine scenarios where this would be useful in hectic, real-world development. However, that should not be the standard for including functionality in Rails. I imagine the Rails core team is constantly having ideas and getting pull requests for small pieces of functionality that could be useful.

They have to balance the usefulness of some feature against the cost of including it in the codebase: supporting it for a few versions, checking backwards compatibility, security vulnerabilities, documentation, etc. There’s a lot of overhead when including something in Rails. The question isn’t if this would be useful; it’s if it would be useful enough.

In my opinion, it would be better to offer this functionality as a separate gem, and if there’s enough interest, you can come back to the core team with a clamoring horde behind you. That said, I think (almost) everything should be piloted as gem before being included in Rails. But I’m just a regular schmoe; core team might have a different opinion.