Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Bugfixes:

Features:
- Your contribution here!
* [#325](https://github.com/bootstrap-ruby/rails-bootstrap-forms/pull/325): Support :prepend and :append for the `select` helper - [@donv](https://github.com/donv).


## [2.6.0][] (2017-02-03)

Expand Down
33 changes: 23 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ This generates the following HTML:
<label for="user_password">Password</label>
<input class="form-control" id="user_password" name="user[password]" type="password">
</div>
<div class="checkbox">
<div class="form-check">
<label for="user_remember_me">
<input name="user[remember_me]" type="hidden" value="0">
<input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1"> Remember me
</label>
</div>
<input class="btn btn-default" name="commit" type="submit" value="Log In">
<input class="btn btn-secondary" name="commit" type="submit" value="Log In">
</form>
```

Expand Down Expand Up @@ -209,7 +209,7 @@ This automatically adds the `has-feedback` class to the `form-group`:

```html
<div class="form-group has-feedback">
<label class="control-label" for="user_login">Login</label>
<label class="form-control-label" for="user_login">Login</label>
<input class="form-control" id="user_login" name="user[login]" type="text" />
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
Expand All @@ -227,7 +227,7 @@ You can also prepend and append buttons. Note: The buttons must contain the
`btn` class to generate the correct markup.

```erb
<%= f.text_field :search, append: link_to("Go", "#", class: "btn btn-default") %>
<%= f.text_field :search, append: link_to("Go", "#", class: "btn btn-secondary") %>
```

To add a class to the input group wrapper, use `:input_group_class` option.
Expand All @@ -249,7 +249,7 @@ Which produces the following output:

```erb
<div class="form-group has-warning" data-foo="bar">
<label class="control-label" for="user_name">Id</label>
<label class="form-control-label" for="user_name">Id</label>
<input class="form-control" id="user_name" name="user[name]" type="text">
</div>
```
Expand All @@ -264,6 +264,19 @@ Our select helper accepts the same arguments as the [default Rails helper](http:
<%= f.select :product, [[1, "Apple"], [2, "Grape"]], { label: "Choose your favorite fruit:" }, { class: "selectpicker" } %>
```

#### Collection select on an association

Validations on foreign key columns used for assigning associations do not by
default know about validation errors on the association itself. This can be
changed by using the `error_key` option, which will look for errors using the
given key rather than the value being assigned to by the select:

```erb
<%= bootstrap_form_for(@user) do |f| %>
<%= f.collection_select(:product_id, Product.all, :id, :name, error_key: :product) %>
<% end %>
```

### Checkboxes and Radios

Checkboxes and radios should be placed inside of a `form_group` to render
Expand Down Expand Up @@ -330,7 +343,7 @@ Here's the output:

```html
<div class="form-group">
<label class="col-sm-2 control-label" for="user_email">Email</label>
<label class="col-sm-2 form-control-label" for="user_email">Email</label>
<div class="col-sm-10">
<p class="form-control-static">test@email.com</p>
</div>
Expand All @@ -355,7 +368,7 @@ this defining these selects as `inline-block` and a width of `auto`.

### Submit Buttons

The `btn btn-default` css classes are automatically added to your submit
The `btn btn-secondary` css classes are automatically added to your submit
buttons.

```erb
Expand Down Expand Up @@ -468,10 +481,10 @@ error will be displayed below the field. Rails normally wraps the fields in a
div (field_with_errors), but this behavior is suppressed. Here's an example:

```html
<div class="form-group has-error">
<label class="control-label" for="user_email">Email</label>
<div class="form-group has-danger">
<label class="form-control-label" for="user_email">Email</label>
<input class="form-control" id="user_email" name="user[email]" type="email" value="">
<span class="help-block">can't be blank</span>
<span class="form-control-feedback">can't be blank</span>
</div>
```

Expand Down
50 changes: 32 additions & 18 deletions lib/bootstrap_form/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,17 @@ def file_field_with_bootstrap(name, options = {})
if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new("4.1.0")
def select_with_bootstrap(method, choices = nil, options = {}, html_options = {}, &block)
form_group_builder(method, options, html_options) do
select_without_bootstrap(method, choices, options, html_options, &block)
prepend_and_append_input(options) do
select_without_bootstrap(method, choices, options, html_options, &block)
end
end
end
else
def select_with_bootstrap(method, choices, options = {}, html_options = {})
form_group_builder(method, options, html_options) do
select_without_bootstrap(method, choices, options, html_options)
prepend_and_append_input(options) do
select_without_bootstrap(method, choices, options, html_options)
end
end
end
end
Expand Down Expand Up @@ -111,6 +115,7 @@ def time_zone_select_with_bootstrap(method, priority_zones = nil, options = {},
def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_value = "0", &block)
options = options.symbolize_keys!
check_box_options = options.except(:label, :label_class, :help, :inline)
check_box_options[:class] = ["form-check-input", check_box_options[:class]].compact.join(' ')

html = check_box_without_bootstrap(name, check_box_options, checked_value, unchecked_value)
label_content = block_given? ? capture(&block) : options[:label]
Expand All @@ -130,10 +135,10 @@ def check_box_with_bootstrap(name, options = {}, checked_value = "1", unchecked_

if options[:inline]
label_class = " #{label_class}" if label_class
label(label_name, html, class: "checkbox-inline#{disabled_class}#{label_class}")
label(label_name, html, class: "form-check-inline#{disabled_class}#{label_class}")
else
content_tag(:div, class: "checkbox#{disabled_class}") do
label(label_name, html, class: label_class)
content_tag(:div, class: "form-check#{disabled_class}") do
label(label_name, html, class: ["form-check-label", label_class].compact.join(" "))
end
end
end
Expand Down Expand Up @@ -192,15 +197,17 @@ def radio_buttons_collection(*args)
def form_group(*args, &block)
options = args.extract_options!
name = args.first
error_name = options.delete(:error_key) || name

options[:class] = ["form-group", options[:class]].compact.join(' ')
options[:class] << " #{error_class}" if has_error?(name)
options[:class] << " row" if get_group_layout(options[:layout]) == :horizontal
options[:class] << " #{error_class}" if has_error?(error_name)
options[:class] << " #{feedback_class}" if options[:icon]

content_tag(:div, options.except(:id, :label, :help, :icon, :label_col, :control_col, :layout)) do
label = generate_label(options[:id], name, options[:label], options[:label_col], options[:layout]) if options[:label]
label = generate_label(options[:id], name, error_name, options[:label], options[:label_col], options[:layout]) if options[:label]
control = capture(&block).to_s
control.concat(generate_help(name, options[:help]).to_s)
control.concat(generate_help(error_name, options[:help]).to_s)
control.concat(generate_icon(options[:icon])) if options[:icon]

if get_group_layout(options[:layout]) == :horizontal
Expand Down Expand Up @@ -259,11 +266,11 @@ def control_class
end

def label_class
"control-label"
"form-control-label"
end

def error_class
"has-error"
"has-danger"
end

def feedback_class
Expand Down Expand Up @@ -309,6 +316,7 @@ def form_group_builder(method, options, html_options = nil)
css_options = html_options || options
control_classes = css_options.delete(:control_class) { control_class }
css_options[:class] = [control_classes, css_options[:class]].compact.join(" ")
css_options[:class] << " form-control-danger" if has_error?(method)

options = convert_form_tag_options(method, options) if acts_like_form_tag

Expand All @@ -318,13 +326,15 @@ def form_group_builder(method, options, html_options = nil)
icon = options.delete(:icon)
label_col = options.delete(:label_col)
control_col = options.delete(:control_col)
error_key = options.delete(:error_key)
layout = get_group_layout(options.delete(:layout))
form_group_options = {
id: options[:id],
help: help,
icon: icon,
label_col: label_col,
control_col: control_col,
error_key: error_key,
layout: layout,
class: wrapper_class
}
Expand Down Expand Up @@ -364,19 +374,19 @@ def convert_form_tag_options(method, options = {})
options
end

def generate_label(id, name, options, custom_label_col, group_layout)
def generate_label(id, name, error_name, options, custom_label_col, group_layout)
options[:for] = id if acts_like_form_tag
classes = [options[:class], label_class]
classes << (custom_label_col || label_col) if get_group_layout(group_layout) == :horizontal
unless options.delete(:skip_required)
classes << "required" if required_attribute?(object, name)
classes << "required" if required_attribute?(object, error_name)
end

options[:class] = classes.compact.join(" ")

if label_errors && has_error?(name)
error_messages = get_error_messages(name)
label_text = (options[:text] || object.class.human_attribute_name(name)).to_s.concat(" #{error_messages}")
if label_errors && has_error?(error_name)
error_messages = get_error_messages(error_name)
label_text = (options[:text] || object.class.human_attribute_name(error_name)).to_s.concat(" #{error_messages}")
label(name, label_text, options.except(:text))
else
label(name, options[:text], options.except(:text))
Expand All @@ -385,12 +395,16 @@ def generate_label(id, name, options, custom_label_col, group_layout)
end

def generate_help(name, help_text)
help_text = get_error_messages(name) if has_error?(name) && inline_errors
return if help_text === false
if has_error?(name) && inline_errors
help_text = get_error_messages(name)
help_klass = 'form-control-feedback'
end
return if help_text == false

help_klass ||= 'form-text text-muted'
help_text ||= get_help_text_by_i18n_key(name)

content_tag(:span, help_text, class: 'help-block') if help_text.present?
content_tag(:span, help_text, class: help_klass) if help_text.present?
end

def generate_icon(icon)
Expand Down
11 changes: 2 additions & 9 deletions lib/bootstrap_form/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,8 @@ def bootstrap_form_for(object, options = {}, &block)
options[:html] ||= {}
options[:html][:role] ||= 'form'

layout = case options[:layout]
when :inline
"form-inline"
when :horizontal
"form-horizontal"
end

if layout
options[:html][:class] = [options[:html][:class], layout].compact.join(" ")
if options[:layout] == :inline
options[:html][:class] = [options[:html][:class], "form-inline"].compact.join(" ")
end

temporarily_disable_field_error_proc do
Expand Down
2 changes: 1 addition & 1 deletion lib/bootstrap_form/helpers/bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module BootstrapForm
module Helpers
module Bootstrap
def submit(name = nil, options = {})
options.reverse_merge! class: 'btn btn-default'
options.reverse_merge! class: 'btn btn-secondary'
super(name, options)
end

Expand Down
Loading