deeply nested content_tag, concat and rails 3
You don't need to ever use concat
.
Each Rails helper returns a string with some html in it:
tag(:br) # "<br>"
So your simplest helper method would be this:
# "<br>"
def br
tag(:br)
end
If you have multiple strings of html just sum them up:
# "<button>Close</button><button>Save</button>"
def modal_buttons
content_tag(:button, "Close") + content_tag(:button, "Save")
end
Note that you can't just call them as they don't modify the view
# "<button>Save</button>"
def modal_buttons
content_tag(:button, "Close") # this won't do anything
content_tag(:button, "Save")
end
For blocks the same rules apply:
# "<div><button>Close</button><button>Save</button></div>"
def modal_footer
content_tag(:div) do
# what block returns will be inside the div
content_tag(:button, "Close") + content_tag(:button, "Save")
end
end
def modal_body
content_tag(:div) do
modal_header + yield + modal_footer
end
end
As a side note, using just Rails helpers to construct the whole view isn't really their intended purpose. They are supposed to help you in dynamic places, static html is better done in ERB templates.
Michael K Madison
Updated on June 15, 2022Comments
-
Michael K Madison almost 2 years
I'm frustrated using Rails 3.2 and making a helper for Bootstrap modals. I don't understand when you need concat versus when you don't sometimes I end up with tags missing and sometimes I end up with a hash with all the options between before and ending tags. When I use concat on any content-tag with a do-end all hell breaks loose. All I want to do is replicate this html:
<div id="stupid_modal" class="modal hide fade" tabindex="-1" data-width="760"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fontello-icon-cancel-1"></i></button> <h4>Modal header</h4> </div> <div class="modal-body"> <div class="page-header"> <p>Test header 1 2 3.</p> </div> <div class="row-fluid"> content here... blah blah </div> </div> <div class="modal-footer"> <button type="button" data-dismiss="modal" class="btn">Close</button> <button type="button" class="btn btn-green">Save changes</button> </div> </div>
I cannot for the life of me get the button in the h4 in the modal header to work out right. Neither can I get the page header to appear in the modal body.
My helper looks like this:
module ModalHelper def modal(css_id, header_text, hidden = true, options = {},&block) class_text = "modal" class_text += " hide fade" if hidden content_tag(:div, :class => 'modal hide fade', :id => css_id, :style => ("display:none;" if hidden)) do concat modal_header(header_text) concat modal_body(&block) concat modal_footer end end def modal_button(link_text, href) modal_caller link_text, href, :button end def modal_link(link_text, href) modal_caller link_text, href end private def modal_caller(link_text, href, type = nil) options = { :"data-toggle" => "modal" } options.merge!({ :class => "btn" }) if type == :button link_to link_text, "#" + href, options end def modal_header(header_text) content_tag(:div, :class => 'modal-header') do concat content_tag(:button,(content_tag(:i, :class => 'fontello-icon-cancel-1')),:class => 'close', :"data-dismiss" => 'modal', :"aria-hidden" => 'true') concat content_tag(:h4, header_text) end end def modal_body(page_header = "") content_tag(:div, :class => 'modal-body') do content_tag(:div, :class => 'page-header') do concat content_tag(:p, page_header) end content_tag(:div, :class => 'row-fluid') do yield end end end def modal_footer content_tag(:div, :class => 'modal-footer') do concat content_tag(:button, 'Close', type: "button", :class => 'btn btn-boo', :"data-dismiss" => 'modal') concat content_tag(:button, 'Save', type: "button", class: 'btn btn-green') end end
end
And the link looks like this:
<%= modal_link "New Stupid Modal", "stupid_modal" %>
And the modal html looks like this:
<%= modal('stupid_modal', 'Shouldnt this work?', submit: true, tabindex: '-1') do %> <% render 'stupid_modal_partials/stupid_modal' %> <% end %>
The output is this:
<button aria-hidden="true" class="close" data-dismiss="modal"><i>{:class=>"fontello-icon-cancel-1"}</i></button>
which looks like this in the page source:
<i>{:class=>"fontello-icon-cancel-1"}</i>
Update:
changing modal_header to this works:
def modal_header(header_text) content_tag(:div, :class => 'modal-header') do concat content_tag(:button,(content_tag(:i, "",:class => 'fontello-icon-cancel-1')),:class => 'close', :"data-dismiss" => 'modal', :"aria-hidden" => 'true') concat content_tag(:h4, header_text) end end
But this doesn't:
def modal_header(header_text) content_tag(:div, :class => 'modal-header') do concat content_tag(:button,:class => 'close', :"data-dismiss" => 'modal', :"aria-hidden" => 'true') do concat content_tag(:i, "",:class => 'fontello-icon-cancel-1') end concat content_tag(:h4, header_text) end end
which begs the question, wzup with concat? and am i missing something -- I also tried empty quotes as the second argument to the button content_tag