Reputation: 2666
I am trying to create a rails FormBuilder to style a form using bootstrap styling:
<div class="form-group has-error">
<label for="exampleInputEmail1">Email address</label>
<div class="input-group>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
<span class="input-group-addon glyphicon glyphicon-user"></span>
</div>
<p class="help-block>can't be blank</p>
</div>
I was able to get the form builder to work when I only had one div tag(excluded the input-group for the traditional bootstrap form. My problem is that I can't get the nested content_tag with the div with class "input-group" to work properly. I have tried adding the elements and wrapping the content_tag in a capture to no avail.
class LargeFormBuilder < ActionView::Helpers::FormBuilder
include ActionView::Helpers::TagHelper
include ActionView::Helpers::CaptureHelper
include ActionView::Helpers::TextHelper
attr_accessor :output_buffer
%w(text_field text_area email_field password_field).each do |form_method|
define_method(form_method) do |*args|
attribute = args[0]
options = args[1] || {}
options[:label] ||= attribute
options[:class] ||= "form-control input-lg"
label_text ||= options.delete(:label).to_s.titleize
content_tag(:div, class: "form-group #{'has-error' if !object.errors[attribute].empty?}") do
concat label(attribute, label_text, class: "control-label")
concat (
content_tag(:div, class: "input-group") do
concat super(attribute, options)
concat content_tag(:span, "", class: "input-group-addon glyphicon glyphicon-user")
end
)
concat errors_for_field(attribute)
end
end
end
def errors_for_field(attribute, options={})
return "" if object.errors[attribute].empty?
content_tag(:p, object.errors[attribute].to_sentence.capitalize, class: "help-block")
end
end
Upvotes: 0
Views: 5746
Reputation: 7042
I think this is a nice example of a 3 layers deep nested content_tag with bootstrap 4 styling. it's a form helper method that takes an action ex. :new or :edit, and outputs available locales using pagination button style of bootstrap 4.
def form_lang_switcher(action)
content_tag(:nav, :"aria-label" => 'language switch') do
content_tag(:ul, class: 'pagination pagination-sm justify-content-end') do
I18n.available_locales.each do |loc|
concat content_tag(:li, (link_to loc.upcase,
url_for(action: :"#{action}", locale: loc),
class: "page-link"),
class: "page-item #{(I18n.locale == loc ? "active" : "")}").html_safe
end
end
end
end
Upvotes: 0
Reputation: 13181
It's much simpler that that in fact you do not need to use concat
you can just use +
to achieve the same result in a clearer way, just be sure that the first string is html_safe
content_tag(:div, class: "form-group #{'has-error' if !object.errors[attribute].empty?}") do
label(attribute, label_text, class: "control-label").html_safe + \
content_tag(:div, class: "input-group") do
concat super(attribute, options)
concat content_tag(:span, "", class: "input-group-addon glyphicon glyphicon-user")
end + \
errors_for_field(attribute)
end
and for even more readability
content_tag(:div, class: "form-group #{'has-error' if !object.errors[attribute].empty?}") do
label_html = label(attribute, label_text, class: "control-label")
input_html = content_tag(:div, class: "input-group") do
concat super(attribute, options)
concat content_tag(:span, "", class: "input-group-addon glyphicon glyphicon-user")
end
error_html = errors_for_field(attribute)
label_html.html_safe + input_html + error_html
end
Upvotes: 6