diff --git a/README.md b/README.md
index c1404a130..d207e64df 100644
--- a/README.md
+++ b/README.md
@@ -81,6 +81,16 @@ If your form is not backed by a model, use the `bootstrap_form_tag`. Usage of th
<% end %>
```
+### bootstrap_form_with
+
+If you are using Rails >= 5.1 just use the `bootstrap_form_with` helper. Here's an example:
+
+```erb
+<%= bootstrap_form_with(model: @user) do |f| %>
+ <%= f.email_field :email %>
+<% end %>
+```
+
## Form Helpers
This gem wraps the following Rails form helpers:
diff --git a/lib/bootstrap_form/helper.rb b/lib/bootstrap_form/helper.rb
index ee73c9016..ed7e5d6c2 100644
--- a/lib/bootstrap_form/helper.rb
+++ b/lib/bootstrap_form/helper.rb
@@ -39,5 +39,29 @@ def temporarily_disable_field_error_proc
ensure
ActionView::Base.field_error_proc = original_proc
end
+
+ if ::Rails::VERSION::STRING >= '5.1'
+ def bootstrap_form_with(options = {}, &block)
+ options.reverse_merge!({builder: BootstrapForm::FormBuilder})
+
+ 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(" ")
+ end
+
+ temporarily_disable_field_error_proc do
+ form_with(options, &block)
+ end
+ end
+ end
end
end
diff --git a/test/bootstrap_form_with_test.rb b/test/bootstrap_form_with_test.rb
new file mode 100644
index 000000000..98d0ebd35
--- /dev/null
+++ b/test/bootstrap_form_with_test.rb
@@ -0,0 +1,139 @@
+require 'test_helper'
+
+if ::Rails::VERSION::STRING >= '5.1'
+ class BootstrapFormWithTest < ActionView::TestCase
+ include BootstrapForm::Helper
+
+ def setup
+ setup_test_fixture
+ end
+
+ test "default-style forms" do
+ expected = %{
}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user) { |f| nil }
+ end
+
+ test "inline-style forms" do
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, layout: :inline) { |f| nil }
+ end
+
+ test "horizontal-style forms" do
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, layout: :horizontal) { |f| f.email_field :email }
+ end
+
+ test "existing styles aren't clobbered when specifying a form style" do
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, layout: :horizontal, html: { class: "my-style" }) { |f| f.email_field :email }
+ end
+
+ test "given role attribute should not be covered by default role attribute" do
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, html: { role: 'not-a-form'}) {|f| nil}
+ end
+
+ test "errors display correctly and inline_errors are turned off by default when label_errors is true" do
+ @user.email = nil
+ @user.valid?
+
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, label_errors: true) { |f| f.text_field :email }
+ end
+
+ test "errors display correctly and inline_errors can also be on when label_errors is true" do
+ @user.email = nil
+ @user.valid?
+
+ expected = %{ost\" role=\"form\">
can't be blank, is too short (minimum is 5 characters)
}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, label_errors: true, inline_errors: true) { |f| f.text_field :email }
+ end
+
+ test "label error messages use humanized attribute names" do
+ I18n.backend.store_translations(:en, {activerecord: {attributes: {user: {email: 'Your e-mail address'}}}})
+
+ @user.email = nil
+ @user.valid?
+
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, label_errors: true, inline_errors: true) { |f| f.text_field :email }
+
+ I18n.backend.store_translations(:en, {activerecord: {attributes: {user: {email: nil}}}})
+ end
+
+ test "alert_message contains the error summary when inline_errors are turned off" do
+ @user.email = nil
+ @user.valid?
+
+ output = bootstrap_form_with(model: @user, inline_errors: false) do |f|
+ f.alert_message('Please fix the following errors:')
+ end
+
+ expected = %{}
+ assert_equivalent_xml expected, output
+ end
+
+ test "alert_message allows the error_summary to be turned off" do
+ @user.email = nil
+ @user.valid?
+
+ output = bootstrap_form_with(model: @user, inline_errors: false) do |f|
+ f.alert_message('Please fix the following errors:', error_summary: false)
+ end
+
+ expected = %{}
+ assert_equivalent_xml expected, output
+ end
+
+ test "alert_message allows the error_summary to be turned on with inline_errors also turned on" do
+ @user.email = nil
+ @user.valid?
+
+ output = bootstrap_form_with(model: @user, inline_errors: true) do |f|
+ f.alert_message('Please fix the following errors:', error_summary: true)
+ end
+
+ expected = %{}
+ assert_equivalent_xml expected, output
+ end
+
+ test "custom label width for horizontal forms" do
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, layout: :horizontal) { |f| f.email_field :email, label_col: 'col-sm-1' }
+ end
+
+ test "offset for form group without label respects label width for horizontal forms" do
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, layout: :horizontal, label_col: 'col-md-2', control_col: 'col-md-10') { |f| f.form_group { f.submit } }
+ end
+
+ test "custom input width for horizontal forms" do
+ expected = %{}
+ assert_equivalent_xml expected, bootstrap_form_with(model: @user, layout: :horizontal) { |f| f.email_field :email, control_col: 'col-sm-5' }
+ end
+
+ test "the field contains the error and is not wrapped in div.field_with_errors when bootstrap_form_with is used" do
+ @user.email = nil
+ @user.valid?
+
+ output = bootstrap_form_with(model: @user) do |f|
+ f.text_field(:email, help: 'This is required')
+ end
+
+ expected = %{}
+ assert_equivalent_xml expected, output
+ end
+
+ test "help is preserved when inline_errors: false is passed to bootstrap_form_with" do
+ @user.email = nil
+ @user.valid?
+
+ output = bootstrap_form_with(model: @user, inline_errors: false) do |f|
+ f.text_field(:email, help: 'This is required')
+ end
+
+ expected = %{}
+ assert_equivalent_xml expected, output
+ end
+ end
+end