# File lib/comfy_bootstrap_form/form_builder.rb, line 311 def primary(value = nil, options = {}, &block) add_css_class!(options, "btn-primary") submit(value, options, &block) end
class ComfyBootstrapForm::FormBuilder
Constants
- DATE_SELECT_HELPERS
- FIELD_HELPERS
Attributes
Bootstrap settings set on the form itself
Public Class Methods
# File lib/comfy_bootstrap_form/form_builder.rb, line 23 def initialize(object_name, object, template, options) @form_bootstrap = ComfyBootstrapForm::BootstrapOptions.new(options.delete(:bootstrap)) super(object_name, object, template, options) end
Public Instance Methods
Wrapper around checkbox. Example usage:
checkbox :agree, bootstrap: {label: {text: "Do you agree?"}}
# File lib/comfy_bootstrap_form/form_builder.rb, line 176 def check_box(method, options = {}, checked_value = "1", unchecked_value = "0") bootstrap = form_bootstrap.scoped(options.delete(:bootstrap)) return super if bootstrap.disabled help_text = draw_help(bootstrap) errors = draw_errors(bootstrap, method) add_css_class!(options, "form-check-input") add_css_class!(options, "is-invalid") if errors.present? label_text = nil if (custom_text = bootstrap.label[:text]).present? label_text = custom_text end fieldset_css_class = "form-group" fieldset_css_class += " row" if bootstrap.horizontal? fieldset_css_class += " #{bootstrap.inline_margin_class}" if bootstrap.inline? content_tag(:fieldset, class: fieldset_css_class) do draw_control_column(bootstrap, offset: true) do if bootstrap.custom_control content_tag(:div, class: "custom-control custom-checkbox") do add_css_class!(options, "custom-control-input") remove_css_class!(options, "form-check-input") concat super(method, options, checked_value, unchecked_value) concat label(method, label_text, class: "custom-control-label") concat errors if errors.present? concat help_text if help_text.present? end else content_tag(:div, class: "form-check") do concat super(method, options, checked_value, unchecked_value) concat label(method, label_text, class: "form-check-label") concat errors if errors.present? concat help_text if help_text.present? end end end end end
Helper to generate multiple checkboxes. Same options as for radio buttons. Example usage:
collection_check_boxes :choices, Choice.all, :id, :label
# File lib/comfy_bootstrap_form/form_builder.rb, line 244 def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}) bootstrap = form_bootstrap.scoped(options.delete(:bootstrap)) return super if bootstrap.disabled content = "".html_safe unless options[:include_hidden] == false content << hidden_field(method, multiple: true, value: "") end args = [bootstrap, :check_box, method, collection, value_method, text_method, options, html_options] content << draw_choices(*args) do |m, v, opts| opts[:multiple] = true opts[:include_hidden] = false check_box(m, opts.merge(bootstrap: { disabled: true }), v) end end
Wrapper for file_field
helper. It can accept `custom_control` option.
file_field :photo, bootstrap: {custom_control: true}
# File lib/comfy_bootstrap_form/form_builder.rb, line 104 def file_field(method, options = {}) bootstrap = form_bootstrap.scoped(options.delete(:bootstrap)) return super if bootstrap.disabled draw_form_group(bootstrap, method, options) do if bootstrap.custom_control content_tag(:div, class: "custom-file") do add_css_class!(options, "custom-file-input") remove_css_class!(options, "form-control") label_text = options.delete(:placeholder) concat super(method, options) label_options = { class: "custom-file-label" } label_options[:for] = options[:id] if options[:id].present? concat label(method, label_text, label_options) end else super(method, options) end end end
Helper method to put arbitrary content in markup that renders correctly for the Bootstrap form. Example:
form_group bootstrap: {label: {text: "Label"}} do "Some content" end
# File lib/comfy_bootstrap_form/form_builder.rb, line 323 def form_group(options = {}) bootstrap = form_bootstrap.scoped(options.delete(:bootstrap)) label_options = bootstrap.label.clone label_text = label_options.delete(:text) label = if label_text.present? if bootstrap.horizontal? add_css_class!(label_options, "col-form-label") add_css_class!(label_options, bootstrap.label_col_class) add_css_class!(label_options, bootstrap.label_align_class) elsif bootstrap.inline? add_css_class!(label_options, bootstrap.inline_margin_class) end content_tag(:label, label_text, label_options) end form_group_class = "form-group" form_group_class += " row" if bootstrap.horizontal? form_group_class += " mr-sm-2" if bootstrap.inline? content_tag(:div, class: form_group_class) do content = "".html_safe content << label if label.present? content << draw_control_column(bootstrap, offset: label.blank?) do yield end end end
Wrapper for the number field. It has default changed from `step: β1β` to `step: βanyβ` to prevent confusion when dealing with decimal numbers.
number_field :amount, step: 5
# File lib/comfy_bootstrap_form/form_builder.rb, line 75 def number_field(method, options = {}) bootstrap = form_bootstrap.scoped(options.delete(:bootstrap)) options.reverse_merge!(step: "any") return super(method, options) if bootstrap.disabled draw_form_group(bootstrap, method, options) do super(method, options) end end
Bootstrap wrapper for readonly text field that is shown as plain text.
plaintext(:value)
# File lib/comfy_bootstrap_form/form_builder.rb, line 265 def plaintext(method, options = {}) bootstrap = form_bootstrap.scoped(options.delete(:bootstrap)) draw_form_group(bootstrap, method, options) do remove_css_class!(options, "form-control") add_css_class!(options, "form-control-plaintext") options[:readonly] = true ActionView::Helpers::FormBuilder.instance_method(:text_field).bind(self).call(method, options) end end
Same as submit button, only with btn-primary class added
Wrapper for select helper. Boostrap options are sent via options hash:
select :choices, ["a", "b"], bootstrap: {label: {text: "Custom"}}
# File lib/comfy_bootstrap_form/form_builder.rb, line 89 def select(method, choices = nil, options = {}, html_options = {}, &block) bootstrap = form_bootstrap.scoped(options.delete(:bootstrap)) return super if bootstrap.disabled add_css_class!(html_options, "custom-select") if bootstrap.custom_control draw_form_group(bootstrap, method, html_options) do super(method, choices, options, html_options, &block) end end
Add bootstrap formatted submit button. If you need to change its type or add another css class, you need to override all css classes like so:
submit(class: "btn btn-info custom-class")
You may add additional content that directly follows the button. Here's an example of a cancel link:
submit do link_to("Cancel", "/", class: "btn btn-link") end
# File lib/comfy_bootstrap_form/form_builder.rb, line 287 def submit(value = nil, options = {}, &block) if value.is_a?(Hash) options = value value = nil end bootstrap = form_bootstrap.scoped(options.delete(:bootstrap)) return super if bootstrap.disabled add_css_class!(options, "btn") form_group_class = "form-group" form_group_class += " row" if bootstrap.horizontal? content_tag(:div, class: form_group_class) do draw_control_column(bootstrap, offset: true) do out = super(value, options) out << capture(&block) if block_given? out end end end
Private Instance Methods
# File lib/comfy_bootstrap_form/form_builder.rb, line 603 def add_css_class!(options, string) css_class = [options[:class], string].compact.join(" ") options[:class] = css_class if css_class.present? end
Rendering of choices for checkboxes and radio buttons
# File lib/comfy_bootstrap_form/form_builder.rb, line 512 def draw_choices(bootstrap, type, method, collection, value_method, text_method, _options, html_options) draw_form_group_fieldset(bootstrap, method) do if bootstrap.custom_control label_css_class = "custom-control-label" form_check_css_class = "custom-control" form_check_css_class += case type when :radio_button then " custom-radio" when :check_box then " custom-checkbox" end form_check_css_class += " custom-control-inline" if bootstrap.check_inline add_css_class!(html_options, "custom-control-input") else label_css_class = "form-check-label" form_check_css_class = "form-check" form_check_css_class += " form-check-inline" if bootstrap.check_inline add_css_class!(html_options, "form-check-input") end errors = draw_errors(bootstrap, method) help_text = draw_help(bootstrap) add_css_class!(html_options, "is-invalid") if errors.present? content = "".html_safe collection.each_with_index do |item, index| item_value = item.send(value_method) item_text = item.send(text_method) content << content_tag(:div, class: form_check_css_class) do concat yield method, item_value, html_options concat label(method, item_text, value: item_value, class: label_css_class) if ((collection.count - 1) == index) && !bootstrap.check_inline concat errors if errors.present? concat help_text if help_text.present? end end end if bootstrap.check_inline content << errors if errors.present? content << help_text if help_text.present? end content end end
Renders control for a given field
# File lib/comfy_bootstrap_form/form_builder.rb, line 433 def draw_control(bootstrap, errors, _method, options) add_css_class!(options, "form-control") add_css_class!(options, "is-invalid") if errors.present? draw_control_column(bootstrap, offset: bootstrap.label[:hide]) do draw_input_group(bootstrap, errors) do yield end end end
Wrapping in control in column wrapper
# File lib/comfy_bootstrap_form/form_builder.rb, line 446 def draw_control_column(bootstrap, offset:) return yield unless bootstrap.horizontal? css_class = bootstrap.control_col_class.to_s css_class += " #{bootstrap.offset_col_class}" if offset content_tag(:div, class: css_class) do yield end end
# File lib/comfy_bootstrap_form/form_builder.rb, line 376 def draw_errors(bootstrap, method) errors = [] if bootstrap.error.present? errors = [bootstrap.error] else return if object.nil? errors = object.errors[method] # If error is on association like `belongs_to :foo`, we need to render it # on an input field with `:foo_id` name. if errors.blank? errors = object.errors[method.to_s.sub(%r{_id$}, "")] end end return if errors.blank? content_tag(:div, class: "invalid-feedback") do errors.join(", ") end end
form group wrapper for input fields
# File lib/comfy_bootstrap_form/form_builder.rb, line 358 def draw_form_group(bootstrap, method, options) label = draw_label(bootstrap, method, for_attr: options[:id]) errors = draw_errors(bootstrap, method) control = draw_control(bootstrap, errors, method, options) do yield end form_group_class = "form-group" form_group_class += " row" if bootstrap.horizontal? form_group_class += " mr-sm-2" if bootstrap.inline? content_tag(:div, class: form_group_class) do concat label concat control end end
Wrapper for collections of radio buttons and checkboxes
# File lib/comfy_bootstrap_form/form_builder.rb, line 567 def draw_form_group_fieldset(bootstrap, method) options = {} unless bootstrap.label[:hide] label_text = bootstrap.label[:text] label_text ||= ActionView::Helpers::Tags::Label::LabelBuilder .new(@template, @object_name.to_s, method, @object, nil).translation add_css_class!(options, "col-form-label pt-0") add_css_class!(options, bootstrap.label[:class]) if bootstrap.horizontal? add_css_class!(options, bootstrap.label_col_class) add_css_class!(options, bootstrap.label_align_class) end label = content_tag(:legend, options) do label_text end end content_tag(:fieldset, class: "form-group") do content = "".html_safe content << label if label.present? content << draw_control_column(bootstrap, offset: bootstrap.label[:hide]) do yield end if bootstrap.horizontal? content_tag(:div, content, class: "row") else content end end end
Drawing boostrap form field help text. Example usage:
text_field(:value, bootstrap: {help: "help text"})
# File lib/comfy_bootstrap_form/form_builder.rb, line 504 def draw_help(bootstrap) text = bootstrap.help return if text.blank? content_tag(:small, text, class: "form-text text-muted") end
Wraps input field in input group container that allows prepending and appending text or html. Example:
text_field(:value, bootstrap: {prepend: "$.$$"}}) text_field(:value, bootstrap: {append: {html: "<button>Go</button>"}}})
# File lib/comfy_bootstrap_form/form_builder.rb, line 462 def draw_input_group(bootstrap, errors, &block) prepend_html = draw_input_group_content(bootstrap, :prepend) append_html = draw_input_group_content(bootstrap, :append) help_text = draw_help(bootstrap) # Not prepending or appending anything. Bail. if prepend_html.blank? && append_html.blank? content = capture(&block) content << errors if errors.present? content << help_text if help_text.present? return content end content = "".html_safe content << content_tag(:div, class: "input-group") do concat prepend_html if prepend_html.present? concat capture(&block) concat append_html if append_html.present? concat errors if errors.present? end content << help_text if help_text.present? content end
# File lib/comfy_bootstrap_form/form_builder.rb, line 487 def draw_input_group_content(bootstrap, type) value = bootstrap.send(type) return unless value.present? content_tag(:div, class: "input-group-#{type}") do if value.is_a?(Hash) && value[:html].present? value[:html] else content_tag(:span, value, class: "input-group-text") end end end
Renders label for a given field. Takes following bootstrap options:
:text - replace default label text :class - css class on the label :hide - if `true` will render for screen readers only
This is how those options can be passed in:
text_field(:value, bootstrap: {label: {text: "Custom", class: "custom"}})
You may also just set the label text by passing a string instead of label hash:
text_field(:value, bootstrap: {label: "Custom Label"})
# File lib/comfy_bootstrap_form/form_builder.rb, line 414 def draw_label(bootstrap, method, for_attr: nil) options = bootstrap.label.dup text = options.delete(:text) options[:for] = for_attr if for_attr.present? add_css_class!(options, "sr-only") if options.delete(:hide) add_css_class!(options, bootstrap.inline_margin_class) if bootstrap.inline? if bootstrap.horizontal? add_css_class!(options, "col-form-label") add_css_class!(options, bootstrap.label_col_class) add_css_class!(options, bootstrap.label_align_class) end label(method, text, options) end
# File lib/comfy_bootstrap_form/form_builder.rb, line 608 def remove_css_class!(options, string) css_class = options[:class].to_s.split(" ") options[:class] = (css_class - [string]).compact.join(" ") options.delete(:class) if options[:class].blank? end