Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
19 changes: 11 additions & 8 deletions lib/bootstrap_form/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,16 @@ 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] << " #{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 @@ -322,13 +323,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 @@ -368,19 +371,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 Down
8 changes: 8 additions & 0 deletions test/bootstrap_selects_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,12 @@ def setup
assert_equivalent_xml expected, @builder.datetime_select(:misc, { include_blank: true }, class: "my-datetime-select")
end
end

test "collection_selects display errors correctly when error_key is set" do
@address = Address.new
@address.valid?

expected = %{<form accept-charset=\"UTF-8\" action=\"/addresses\" class=\"new_address\" id=\"new_address\" method=\"post\" role=\"form\"><div style=\"margin:0;padding:0;display:inline\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" /></div><div class=\"form-group has-error\"><label class=\"control-label required\" for=\"address_user_id\">User can&#39;t be blank</label><select class=\"form-control\" id=\"address_user_id\" name=\"address[user_id]\"></select><span class=\"help-block\">can&#39;t be blank</span></div></form>}
assert_equivalent_xml expected, bootstrap_form_for(@address, url: "/addresses", label_errors: true, inline_errors: true) { |f| f.collection_select :user_id, [], :id, :email, error_key: :user }
end
end
1 change: 1 addition & 0 deletions test/dummy/app/models/address.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
class Address < ActiveRecord::Base
belongs_to :user
validates :user, presence: true
end