Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
4255abb
has-error is now has-danger
desheikh Nov 8, 2016
d8c3c1d
inputs with errors should have form-control-feedback
desheikh Nov 8, 2016
04388cf
control-label is now form-control-label
desheikh Nov 8, 2016
47e90fa
btn-default is now btn-secondary
desheikh Nov 8, 2016
2fe6f28
form-horizontal is no longer a required class
desheikh Nov 8, 2016
fd2dc57
input field should have form-control-danger on error
desheikh Nov 8, 2016
77ed9ff
checkbox is now form-check
desheikh Nov 8, 2016
edac96a
checkbox input should have form-check-input
desheikh Nov 8, 2016
7d4043e
non inline checkbox labels should have form-check-label
desheikh Nov 8, 2016
16d82d6
Support :prepend and :append for the `select` helper (#327)
donv Apr 24, 2017
4c83ea2
Merge remote-tracking branch 'upstream/master' into bootstrap-4-rails…
lcreid Aug 28, 2017
5d4dec3
`form_with` mostly working.
lcreid Aug 28, 2017
41e1c79
Make it parse under Ruby 1.9.2
lcreid Sep 14, 2017
7fbe027
Try another way to fix Ruby 1.9.2 parse problem.
lcreid Sep 14, 2017
ace7723
Try Ruby 1.9.2 syntax yet again.
lcreid Sep 14, 2017
33ea133
Close, but going to try keying on Rails ID generation.
lcreid Sep 21, 2017
ce707de
Using the underlying option for id generation works.
lcreid Sep 21, 2017
9a45e86
Use fields instead of fields_for.
lcreid Sep 21, 2017
f9ebdec
Finally remove FormBuilderFormWith.
lcreid Sep 21, 2017
efd1122
Remove some unnecessary diffs.
lcreid Oct 7, 2017
637248a
Merge remote-tracking branch 'upstream/master' into bootstrap-4-rails…
lcreid Jan 9, 2018
75a9c39
Fix select test case for :prepend, :append.
lcreid Jan 9, 2018
c9fca28
Fix test case that hadn't been converted to form_with.
lcreid Jan 11, 2018
17259d1
Documentation tests.
lcreid Jan 11, 2018
1a1e4ec
Fix out-of-date HTML in test case.
lcreid Jan 11, 2018
fb2c3e0
Merge remote-tracking branch 'upstream/master' into bootstrap-4-rails…
lcreid Jan 11, 2018
4e1664b
Uncomment and fix Rails 5.1 collection_radio_button tests.
lcreid Jan 11, 2018
c2e8473
Merge branch 'minitest' into bootstrap-4-rails-5-1
lcreid Jan 11, 2018
db3ed98
Fix README to remove false statements about 5.2.
lcreid Jan 11, 2018
35606bb
heredoc
lcreid Jan 11, 2018
8f2973d
bootstrap_form_with_test working with 5.1 and 5.2.
lcreid Jan 12, 2018
d0f81bf
Handle Rails 5.1 and 5.2+.
lcreid Jan 12, 2018
300c8cf
Use heredoc.strip.
lcreid Jan 12, 2018
88858be
Comments and more heredoc formatting.
lcreid Jan 12, 2018
7881fbe
Merge branch 'master' into bootstrap-4-rails-5-1
lcreid Jan 16, 2018
6642309
Partially updated test cases.
lcreid Jan 16, 2018
62904ab
Don't add class="" to label if no classes specified.
lcreid Jan 16, 2018
4f89877
Merge branch 'empty-class-on-label' into bootstrap-4-rails-5-1
lcreid Jan 16, 2018
855764f
Intermediate check-in.
lcreid Jan 16, 2018
fa3fd46
Intermediate.
lcreid Jan 16, 2018
749b297
Intermediate.
lcreid Jan 16, 2018
71b8237
Intermediate.
lcreid Jan 17, 2018
1087a94
Most of custom IDs working.
lcreid Jan 17, 2018
fcb71ca
Uncomment test cases.
lcreid Jan 17, 2018
d02e1b7
Merge branch 'master' into empty-class-on-label
lcreid Jan 17, 2018
84c0591
Resolve conflicts.
lcreid Jan 17, 2018
f8f18c3
Merge branch 'empty-class-on-label' into bootstrap-4-rails-5-1
lcreid Jan 17, 2018
287d2a4
Saving work with tests red and debugging.
lcreid Jan 18, 2018
606ee0d
Commit before saving to future branch.
lcreid Jan 18, 2018
e55246b
Delete redundant test files.
lcreid Jan 18, 2018
6b9d6f7
Remove puts and TODOs.
lcreid Jan 18, 2018
855e948
Tests passing up to Rails 5.1.
lcreid Jan 18, 2018
72e1aac
Some tests for form_with. All pass.
lcreid Jan 19, 2018
2607af9
Documentation tested.
lcreid Jan 19, 2018
710cf10
Update Rails 5.1 examples in documentation.
lcreid Jan 19, 2018
1b15bb5
Merge remote-tracking branch 'upstream/master' into bootstrap-4-rails…
lcreid Jan 19, 2018
ac7d2bc
Pin minitest to exactly 5.10.1 for Rails 5.0.
lcreid Jan 19, 2018
f315716
Fence off one form_with test.
lcreid Jan 19, 2018
14c74a4
Add tests for fields method. Pass when they shouldn't.
lcreid Jan 20, 2018
f766d0b
Merge remote-tracking branch 'upstream/master' into bootstrap-4-rails…
lcreid Jan 21, 2018
69e76ab
Merge remote-tracking branch 'upstream/master' into bootstrap-4-rails…
lcreid Jan 21, 2018
e86b7f9
Go back to using minitest 5.10.3 to do bisect.
lcreid Jan 22, 2018
7f97507
Merge branch 'master' into bootstrap-4-rails-5-1
lcreid Jan 23, 2018
102cc54
Merge remote-tracking branch 'upstream/master' into bootstrap-4-rails…
lcreid Jan 23, 2018
fc2db34
Test only form_for in one case.
lcreid Jan 23, 2018
df5dd0d
Test and show that bootstrap_form fields helper not needed
lcreid Jan 23, 2018
0991706
Merge branch 'master' into bootstrap-4-rails-5-1
lcreid Jan 25, 2018
2855154
Remove unwanted tests.
lcreid Jan 25, 2018
f85f628
Feedback from review.
lcreid Jan 25, 2018
b01a5f4
Minimize test cases.
lcreid Jan 25, 2018
b81c30b
Fix mistaken commit of version.
lcreid Jan 25, 2018
af121f3
Remove code per review.
lcreid Jan 25, 2018
4a028c5
Remove duplicate CHANGELOG entry
mattbrictson Jan 26, 2018
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ In addition to these necessary markup changes, the bootstrap_form API itself has

### New features

* Support for Rails 5.1 `form_with` - [@lcreid](https://github.com/lcreid).
* Support Bootstrap v4's [Custom Checkboxes and Radios](https://getbootstrap.com/docs/4.0/components/forms/#checkboxes-and-radios-1) with a new `custom: true` option
* Allow HTML in help translations by using the `_html` suffix on the key - [@unikitty37](https://github.com/unikitty37)
* Your contribution here!
Expand Down
49 changes: 48 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Bootstrap v4-style forms into your Rails application.
## Requirements

* Ruby 2.2.2+
* Rails 5.0+
* Rails 5.0+ (Rails 5.1+ for `bootstrap_form_with`)
* Bootstrap 4.0.0+

## Installation
Expand Down Expand Up @@ -84,6 +84,53 @@ If your form is not backed by a model, use the `bootstrap_form_tag`. Usage of th
<% end %>
```

### `bootstrap_form_with` (Rails 5.1+)

Note that `form_with` in Rails 5.1 does not add IDs to form elements and labels by default, which are both important to Bootstrap markup. This behavior is corrected in Rails 5.2.

To get started, just use the `bootstrap_form_with` helper in place of `form_with`. Here's an example:

```erb
<%= bootstrap_form_with(model: @user, local: true) do |f| %>
<%= f.email_field :email %>
<%= f.password_field :password %>
<%= f.check_box :remember_me %>
<%= f.submit "Log In" %>
<% end %>
```

This generates:

```html
<form role="form" action="/users" accept-charset="UTF-8" method="post">
<input name="utf8" type="hidden" value="&#x2713;" />
<div class="form-group">
<label class="required" for="user_email">Email</label>
<input class="form-control" type="email" value="steve@example.com" name="user[email]" />
</div>
<div class="form-group">
<label for="user_password">Password</label>
<input class="form-control" type="password" name="user[password]" />
<small class="form-text text-muted">A good password should be at least six characters long</small>
</div>
<div class="form-check">
<label class="form-check-label" for="user_remember_me">
<input name="user[remember_me]" type="hidden" value="0" />
<input class="form-check-input" type="checkbox" value="1" name="user[remember_me]" /> Remember me</label>
</div>
<input type="submit" name="commit" value="Log In" class="btn btn-secondary" data-disable-with="Log In" />
</form>
```

`bootstrap_form_with` supports both the `model:` and `url:` use cases
in `form_with`.

`form_with` has some important differences compared to `form_for` and `form_tag`, and these differences apply to `bootstrap_form_with`. A good summary of the differences can be found at: https://m.patrikonrails.com/rails-5-1s-form-with-vs-old-form-helpers-3a5f72a8c78a, or in the [Rails documentation](api.rubyonrails.org).

### Future Compatibility

The Rails team has [suggested](https://github.com/rails/rails/issues/25197) that `form_for` and `form_tag` may be deprecated and then removed in future versions of Rails. `bootstrap_form` will continue to support `bootstrap_form_for` and `bootstrap_form_tag` as long as Rails supports `form_for` and `form_tag`.

## Form Helpers

This gem wraps the following Rails form helpers:
Expand Down
25 changes: 18 additions & 7 deletions lib/bootstrap_form/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,10 @@ def form_group(*args, &block)
end

def fields_for_with_bootstrap(record_name, record_object = nil, fields_options = {}, &block)
fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
if record_object.is_a?(Hash) && record_object.extractable_options?
fields_options = record_object
record_object = nil
end
fields_options[:layout] ||= options[:layout]
fields_options[:label_col] = fields_options[:label_col].present? ? "#{fields_options[:label_col]}" : options[:label_col]
fields_options[:control_col] ||= options[:control_col]
Expand All @@ -246,6 +249,10 @@ def fields_for_with_bootstrap(record_name, record_object = nil, fields_options =

bootstrap_method_alias :fields_for

# the Rails `fields` method passes its options
# to the builder, so there is no need to write a `bootstrap_form` helper
# for the `fields` method.

private

def horizontal?
Expand Down Expand Up @@ -357,11 +364,11 @@ def form_group_builder(method, options, html_options = nil)
label_text ||= options.delete(:label)
end

form_group_options.merge!(label: {
form_group_options[:label] = {
text: label_text,
class: label_class,
skip_required: options.delete(:skip_required)
})
}
end

form_group(method, form_group_options) do
Expand All @@ -370,12 +377,18 @@ def form_group_builder(method, options, html_options = nil)
end

def convert_form_tag_options(method, options = {})
options[:name] ||= method
options[:id] ||= method
unless @options[:skip_default_ids]
options[:name] ||= method
options[:id] ||= method
end
options
end

def generate_label(id, name, options, custom_label_col, group_layout)
# id is the caller's options[:id] at the only place this method is called.
# The options argument is a small subset of the options that might have
# been passed to generate_label's caller, and definitely doesn't include
# :id.
options[:for] = id if acts_like_form_tag
classes = [options[:class]]

Expand All @@ -398,7 +411,6 @@ def generate_label(id, name, options, custom_label_col, group_layout)
else
label(name, options[:text], options.except(:text))
end

end

def generate_help(name, help_text)
Expand Down Expand Up @@ -467,6 +479,5 @@ def get_help_text_by_i18n_key(name)
help_text
end
end

end
end
32 changes: 26 additions & 6 deletions lib/bootstrap_form/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ module Helper
def bootstrap_form_for(object, options = {}, &block)
options.reverse_merge!({builder: BootstrapForm::FormBuilder})

options[:html] ||= {}
options[:html][:role] ||= 'form'

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

temporarily_disable_field_error_proc do
form_for(object, options, &block)
Expand All @@ -22,6 +17,31 @@ def bootstrap_form_tag(options = {}, &block)
bootstrap_form_for("", options, &block)
end

def bootstrap_form_with(options = {}, &block)
options.reverse_merge!(builder: BootstrapForm::FormBuilder)

options = process_options(options)

temporarily_disable_field_error_proc do
form_with(options, &block)
end
end

private

def process_options(options)
options[:html] ||= {}
options[:html][:role] ||= 'form'

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

options
end

public

def temporarily_disable_field_error_proc
original_proc = ActionView::Base.field_error_proc
ActionView::Base.field_error_proc = proc { |input, instance| input }
Expand Down
25 changes: 25 additions & 0 deletions test/bootstrap_fields_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,30 @@ class BootstrapFieldsTest < ActionView::TestCase
assert_equivalent_xml expected, @builder.text_area(:comments)
end

if ::Rails::VERSION::STRING > '5.1' && ::Rails::VERSION::STRING < '5.2'
test "text areas are wrapped correctly form_with Rails 5.1" do
expected = <<-HTML.strip_heredoc
<div class="form-group">
<label for="user_comments">Comments</label>
<textarea class="form-control" name="user[comments]">\nmy comment</textarea>
</div>
HTML
assert_equivalent_xml expected, form_with_builder.text_area(:comments)
end
end

if ::Rails::VERSION::STRING > '5.2'
test "text areas are wrapped correctly form_with Rails 5.2+" do
expected = <<-HTML.strip_heredoc
<div class="form-group">
<label for="user_comments">Comments</label>
<textarea class="form-control" id="user_comments" name="user[comments]">\nmy comment</textarea>
</div>
HTML
assert_equivalent_xml expected, form_with_builder.text_area(:comments)
end
end

test "text fields are wrapped correctly" do
expected = <<-HTML.strip_heredoc
<div class="form-group">
Expand Down Expand Up @@ -250,6 +274,7 @@ class BootstrapFieldsTest < ActionView::TestCase
test "fields_for correctly passes inline style from parent builder" do
@user.address = Address.new(street: '123 Main Street')

# NOTE: This test works with even if you use `fields_for_without_bootstrap`
output = bootstrap_form_for(@user, layout: :inline) do |f|
f.fields_for :address do |af|
af.text_field(:street)
Expand Down
13 changes: 13 additions & 0 deletions test/bootstrap_form_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ class BootstrapFormTest < ActionView::TestCase
assert_equivalent_xml expected, bootstrap_form_for(@user) { |f| nil }
end

if ::Rails::VERSION::STRING >= '5.1'
# No need to test 5.2 separately for this case, since 5.2 does *not*
# generate a default ID for the form element.
test "default-style forms bootstrap_form_with Rails 5.1+" do
expected = <<-HTML.strip_heredoc
<form accept-charset="UTF-8" action="/users" data-remote="true" method="post" role="form">
<input name="utf8" type="hidden" value="&#x2713;" />
</form>
HTML
assert_equivalent_xml expected, bootstrap_form_with(model: @user) { |f| nil }
end
end

test "inline-style forms" do
expected = <<-HTML.strip_heredoc
<form accept-charset="UTF-8" action="/users" class="form-inline" id="new_user" method="post" role="form">
Expand Down
8 changes: 7 additions & 1 deletion test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ def setup_test_fixture
})
end

# Originally only used in one test file but placed here in case it's needed in others in the future.
def form_with_builder
builder = nil
bootstrap_form_with(model: @user) { |f| builder = f }
builder
end

def sort_attributes doc
doc.dup.traverse do |node|
if node.is_a?(Nokogiri::XML::Element)
Expand Down Expand Up @@ -86,5 +93,4 @@ def assert_equivalent_xml(expected, actual)
).to_s(:color)
}
end

end