patternrubyrailsMinor
Table rendering helper
Viewed 0 times
helperrenderingtable
Problem
I wrote this little helper to render a table, however, working with nested
For example
That's the only way I could make it work, without overusing concat. This code smells off, how do I refactor it?
I would also like to extract
content_tag is messy.def semantic_table(table_headers)
content_tag(:table, class: 'ui basic striped table') do
(content_tag :thead do
content_tag(:tr) do
table_headers.each { |h| concat content_tag(:th, h) }
end
end).+ content_tag(:tbody) { yield }
end
endFor example
# users/index.html.slim
= semantic_table ['Username', 'Email', 'Registration date'] do
= render @usersThat's the only way I could make it work, without overusing concat. This code smells off, how do I refactor it?
I would also like to extract
_user.html.slim partial's functionality to the helper, though I don't know how# _user.html.slim
tr
td = link_to user.name, user
td = mail_to user.email
td = time_tag user.created_atSolution
The answer, which may not be what you were hoping to hear, is that for generating more than a couple lines of HTML, partials are a much better fit than
...and then make your helper render it with the given arguments:
Helpers are great for encapsulating logic that doesn't belong in a view/partial or in the controller, or adds a lot of noise: formatting data, choosing/combining several attributes, that sort of thing. But when you just want to spit out a bunch of boring HTML, you can't really beat a simple partial.
Edit
Re: your comment, that's interesting. I'm guessing Rails is using
There may be a workaround that I'm not thinking of, but barring that, the simplest solution is to drop the helper entirely and just use the partial directly in your view:
I'm not 100% sure that'll work, since didn't anticipate the other issue, but I think it will.
Another solution is to get rid of the block and pass in the objects directly:
...and then in the partial call
Of course, this is more constraining than a block, but it may suffice for your use case.
content_tag et al. Put your table code in a partial in e.g. views/shared/_semantic_table.slim.html:table class="ui basic striped table"
thead
tr
- headers.each do |header|
th = header
tbody
= yield...and then make your helper render it with the given arguments:
def semantic_table(headers, &block)
render partial: "shared/semantic_table",
locals: { headers: headers }, &block
endHelpers are great for encapsulating logic that doesn't belong in a view/partial or in the controller, or adds a lot of noise: formatting data, choosing/combining several attributes, that sort of thing. But when you just want to spit out a bunch of boring HTML, you can't really beat a simple partial.
Edit
Re: your comment, that's interesting. I'm guessing Rails is using
instance_eval somewhere, so your block with render @users is being evaluated in some different context where @users is nil. This is surprising, but I don't have a computer in front of me to dig further.There may be a workaround that I'm not thinking of, but barring that, the simplest solution is to drop the helper entirely and just use the partial directly in your view:
= render partial: "shared/semantic_table", locals: { headers: headers } do
= render @usersI'm not 100% sure that'll work, since didn't anticipate the other issue, but I think it will.
Another solution is to get rid of the block and pass in the objects directly:
def semantic_table(headers, objects)
render partial: "shared/semantic_table",
locals: { headers: headers, objects: objects }
end...and then in the partial call
render objects instead of yield.Of course, this is more constraining than a block, but it may suffice for your use case.
Code Snippets
table class="ui basic striped table"
thead
tr
- headers.each do |header|
th = header
tbody
= yielddef semantic_table(headers, &block)
render partial: "shared/semantic_table",
locals: { headers: headers }, &block
end= render partial: "shared/semantic_table", locals: { headers: headers } do
= render @usersdef semantic_table(headers, objects)
render partial: "shared/semantic_table",
locals: { headers: headers, objects: objects }
endContext
StackExchange Code Review Q#108693, answer score: 3
Revisions (0)
No revisions yet.