diff --git a/README.md b/README.md index c1404a130..0d0871ff2 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/lib/bootstrap_form/form_builder.rb b/lib/bootstrap_form/form_builder.rb index e127c7bb3..39581147b 100644 --- a/lib/bootstrap_form/form_builder.rb +++ b/lib/bootstrap_form/form_builder.rb @@ -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 @@ -322,6 +323,7 @@ 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], @@ -329,6 +331,7 @@ def form_group_builder(method, options, html_options = nil) icon: icon, label_col: label_col, control_col: control_col, + error_key: error_key, layout: layout, class: wrapper_class } @@ -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)) diff --git a/test/bootstrap_selects_test.rb b/test/bootstrap_selects_test.rb index 872dfb46e..12670e2e7 100644 --- a/test/bootstrap_selects_test.rb +++ b/test/bootstrap_selects_test.rb @@ -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 = %{
can't be blank
} + 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 diff --git a/test/dummy/app/models/address.rb b/test/dummy/app/models/address.rb index 2c0c20b88..e5759528d 100644 --- a/test/dummy/app/models/address.rb +++ b/test/dummy/app/models/address.rb @@ -1,3 +1,4 @@ class Address < ActiveRecord::Base belongs_to :user + validates :user, presence: true end