-
Notifications
You must be signed in to change notification settings - Fork 355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for Rails 5.1 form_with
#369
Support for Rails 5.1 form_with
#369
Conversation
) * Support :prepend and :append for the `select` helper Fixes bootstrap-ruby#147 * Bootstrap 4 has renamed `control-label` to `form-control-label`
The main changes were around the fact that `form_with` doesn't automatically add class and id attributes in many places that the other form builders did. Added a `for:` to the label options if an ID was specified for the input element, so that the label would get the correct value for the `for` attribute. Sub-classed the form builder to override methods to make `form_with` work without the default Rails-generated DOM IDs.
The `bootstrap_form_with` helper uses Ruby 2+ syntax. I put a test for the Rails version, so the helper is only parse if running Rails 5.1+.
Remove confusing comment. Remove some more unnecessary diffs.
README.md
Outdated
</label> | ||
</div> | ||
<input type="submit" name="commit" value="Log In" class="btn btn-secondary" data-disable-with="Log In" /> | ||
</form> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is duplication. Should be sufficient to to say that bootstrap_form_with
is the same thing as bootstrap_form_for
and the only difference being that it takes same arguments as form_with
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Stand-alone" bootstrap_form_with
documentation should be easier to update when bootstrap_form_for
goes away. Also, users often appreciate examples they can just cut and paste.
README.md
Outdated
</form> | ||
``` | ||
|
||
#### Important Differences Between `form_with` and `form_for` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to Rails documentation would be enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some users may appreciate a summary of the differences/tricks about using form_with
versus form_for
. If everyone things this is overly redundant or pedantic, by all means I'll remove it.
README.md
Outdated
the same way `form_for` and `form_tag` would do by default, | ||
you need to specify `local: true` as an option to `form_with`. | ||
|
||
##### No Default DOM IDs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's out-of-date and incorrect.
Edit: Correct for 5.1, not correct for 5.2 (rails/rails@d3893ec) unless it gets back-ported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this. I saw that the Rails PR had been merged, but in my rush to submit this PR, I didn't fix the README.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've fixed up the README. I need to test against Rails 5.2. Will I be able to do that after #366 is merged, or do I need to figure out how to test against Rails 5.2 myself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just temporarily add gem "rails", "5.2.0.beta3"
in Gemfile to test it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @GBH . I could only find beta2 on rubygems.org, but that's good enough for me for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to slow down and read stuff instead of jumping to conclusions. The commit @GBH referenced (rails/rails@d3893ec) is not the commit I thought it was. I will have to rethink this. The commit makes Rails 5.2+ easier to work with, but I'll have to think about how to document Rails 5.1 and form_with
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like every form_with
test may have to have a 5.1 and 5.2+ version. There's already too much duplication to test form_with
and form_for
. I'll think about this, but if anyone has any suggestions, I'd love to hear them.
tl;dr of the problem: form_with
in Rails 5.1 doesn't generate any DOM IDs in the HTML. It looks like form_with
in Rails 5.2 is going back to generating DOM IDs in the HTML by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is, you don't need to duplicate every single test there is. It's enough to make one for textfield and assume that all others work the same.
# expected = %{<div class="form-group"><label class="form-control-label" for="user_misc">Misc</label><div class="radio"><label for="user_misc_address_1"><input id="user_misc_address_1" name="user[misc]" type="radio" value="address_1" /> Foo</label></div><div class="radio"><label for="user_misc_address_2"><input id="user_misc_address_2" name="user[misc]" type="radio" value="address_2" /> Bar</label></div></div>} | ||
# | ||
# assert_equivalent_xml expected, @form_with_builder.collection_radio_buttons(:misc, collection, lambda { |a| "address_#{a.id}" }, :street) | ||
# end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented out tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this. I will uncomment, but I will also have to figure out what to do about the DOM IDs mentioned above.
Rails 5.2 not tested yet.
form_with
form_with
@lcreid I understand what you are aiming for with the testing approach, but it is a lot to do in a single PR along with all the other form_with stuff. I think I'd rather start by:
I'm comfortable hacking with git, so I am happy to patch together a new branch that contains the existing work you've done for all of those and retains your authorship of the commits. I would argue that this first pass might almost be "good enough" to ship for 4.0.0 alpha; we'll probably need a follow-up PR to add |
@mattbrictson that's exactly my thinking. Sorry if my comments are a bit all over the place. In fact, I'd argue that this PR does what you're suggesting, without any more hacking on your part. I'm working on resolving the conflicts from this morning's merges. I had a small problem that I think is due to the Vagrant box I'm using for this work. (I could push something right now, but I'm not 100 percent sure it would pass Travis). I'll ping you shortly with an update on the status. |
Sorry. Every time I pull in a merge, I've got to deal with a broken test. In order to do so properly, I need a bit more time. I hope to push something by end of day Pacific Time. |
I pushed a conflict-free version, but it should fail on Travis. I expect one failure on all versions of Rails, and an additional failure only on Rails 5.1.4. @mattbrictson I'd appreciate your help, and I will try to look at this later today. |
I had a chance to check, and those are the failures I expected. I'll be back on this later tonight. |
The time zone text strings have an "&" in them. When it's converted to XML and then back to a string, the "&" gets lost.
This is ready for review prior to merge. As discussed above, I will continue to work on enhancing the testing of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am slowly trying to unpack this PR. Apologies for the delay.
I want to make sure the PR is as narrowly-focused as possible, meaning the code changes are the minimum required to support form_with
scenarios and don't have any effects on existing form_for
usage. The fact that form_builder.rb
has modifications has me concerned about unintended consequences.
It seems that most of the changes to form_builder.rb
are code formatting, comments, or syntax tweaks. Otherwise there are only two minor behavioral changes that I can see. Could you help me understand what they do?
lib/bootstrap_form/form_builder.rb
Outdated
@@ -314,6 +325,7 @@ def required_attribute?(obj, attribute) | |||
def form_group_builder(method, options, html_options = nil) | |||
options.symbolize_keys! | |||
html_options.symbolize_keys! if html_options | |||
options[:id] = html_options[:id] if html_options && @options[:skip_default_ids] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain why this line is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure this is part my attempt to handle what is more elegantly handled in #357. The (minimized) tests pass without this line, so I'll take it out.
lib/bootstrap_form/form_builder.rb
Outdated
# 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 || id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am also having trouble figuring out this part. If id
is present, then it will be assigned regardless of whether acts_like_form_tag
is true or false. Why is the acts_like_form_tag
check needed at all, then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was to address part of the consequence of no default IDs in Rails 5.1 form_with
. I'll take this out, and let it be handled by #357. And yes, the acts_like_form_tag
becomes redundant when I added || id
. "Doh!" I don't know what I was thinking. :-)
Gemfile
Outdated
@@ -11,7 +11,7 @@ end | |||
|
|||
group :test do | |||
# can relax version requirement for Rails 5.2.beta3+ | |||
gem "minitest", "~> 5.10.3" | |||
gem "minitest", "5.10.3" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could be wrong, but since 5.10.3 is the only version that matches the ~> 5.10.3
constraint, this change has no actual effect, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry. This was part of some flailing I did around the Minitest versions, and I shouldn't have let it slip through to the PR. :-(
README.md
Outdated
@@ -13,7 +13,7 @@ Bootstrap v4-style forms into your Rails application. | |||
## Requirements | |||
|
|||
* Ruby 2.3+ | |||
* Rails 5.0+ | |||
* Rails 5.0+ (Rails 5.1+ for `bootstrap_form_with`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
README.md
Outdated
@@ -40,6 +40,138 @@ Then require the CSS in your `application.css` file: | |||
|
|||
## Usage | |||
|
|||
### Rails >= 5.1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think we should go as far as recommend form_with
for Rails 5.1. IMHO the form_with
released in 5.1 is fundamentally broken as it does not include IDs. I personally would wait until 5.2 to make the leap from form_for
to form_with
.
Perhaps we could re-title this section with a caveat:
### `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.
And place it after the section where we describe:
### `bootstrap_form_for` (Rails 5.0+)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I wrote the README relatively early in my work on this PR, and once I actually started to use form_with
in my own app I was feeling that form_with
in 5.1 wasn't really ready for prime time.
<input type="submit" name="commit" value="Log In" class="btn btn-secondary" data-disable-with="Log In" /> | ||
</form> | ||
``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is sufficient to stop here, with a note that says that both model:
and url:
styles are supported. We don't need to reproduce all the Rails documentation. (Perhaps a link to the appropriate section of the Rails doc would be nice.) In particular, I would remove these sections as well:
- Important Differences Between
form_with
andform_for
- Ajax by Default
- No Default DOM IDs
- Use
fields
Instead Offields_for
In Nested Forms - No Default Classes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Back in September, when I was first trying my fork with bootstrap_form_with
, this section brought together the things I was learning about form_with
versus form_for
. But now I'm sure I can find a good link to differences, so I'll take this section out and replace it with a link or two to other documentation.
README.md
Outdated
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`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great clarification 👍
Could you remove the hard line wrap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry. An old nroff
habit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for asking you to trim so much of this PR, but I think getting the essence of it merged is the best path forward. We can iterate with small, targeted PRs from here and hopefully cut down on future review time.
test/documentation_test.rb
Outdated
assert_equivalent_xml expected, actual | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you are going for with this test. As Bootstrap and Rails change, the examples in the README will become out of date, which potentially misleads or confusion people learning about the gem. It also reflects poorly on the project if the README is inaccurate.
However I'm not convinced this is the best solution. I'd like to remove this from this PR and save it for future consideration.
test/bootstrap_radio_button_test.rb
Outdated
@@ -14,7 +14,7 @@ class BootstrapRadioButtonTest < ActionView::TestCase | |||
</label> | |||
</div> | |||
HTML | |||
assert_equivalent_xml expected, @builder.radio_button(:misc, '1', label: 'This is a radio button') | |||
assert_with_builder_radio(expected, :misc, '1', label: 'This is a radio button') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that this test file has to change at all as a result of adding form_with
indicates to me that there is a little too much going on in this PR. Adding one new feature (bootstrap_form_with
) should mean adding one new set of tests. It should not require existing tests to be rewritten. I would prefer to see these tests left alone and the assert_with_builder_radio
and assert_with_builder
helpers excluded from this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove all testing for bootstrap_form_with
and fields
other than the two cases you mentioned above. I'll continue to work on my testing branch and see if I still feel there's a need for more testing.
I've come around to the idea of making this PR minimal, so that's what I'll do. FWIW, the reasons why I wrote more extensive tests are:
- If
form_with
is someday going to replaceform_for
andform_tag
, then I thought it would be better write a complete set ofbootstrap_form_with
tests while I had my head in the problem, rather than leaving it to someone else, five years from now, to figure out how to migrate thebootstrap_form_for
tests tobootstrap_form_with
- Back in August I understood very little of this gem, and wanted to make sure I wasn't breaking anything
- When I tried to use
bootstrap_form_with
in my app, lots of stuff broke. Most of it turned out to be due to the differences betweenform_for
andform_with
, but I didn't figure that out until after I wrote some tests forbootstrap_form_with
- General distrust of myself any time I think that, "I only need to test this one little difference". :-)
And I really appreciate the feedback, so keep the comments coming!
test/bootstrap_fields_test.rb
Outdated
# This test demonstrates that 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. If this test fails, it probably means you have to | ||
# write a `fields` helper in `lib/bootstrap_form/form_builder.rb`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this test was written to investigate Rails behavior, and is now no longer needed. Would you agree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had the same thought, but then I thought it would also serve to test the assumption going forward and give us a warning if something changes in a future Rails version that the assumption is no longer valid. I think there's value to leave it in (perhaps with a better comment to make the intent clearer), but if you want it removed I'll certainly do so.
test/bootstrap_fields_test.rb
Outdated
@@ -201,6 +202,17 @@ class BootstrapFieldsTest < ActionView::TestCase | |||
</form> | |||
HTML | |||
assert_equivalent_xml expected, output | |||
|
|||
## TODO: DRY up the tests for the _with version | |||
if Gem::Version.new(::Rails::VERSION::STRING).release >= Gem::Version.new('5.1.0') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless we have reason to believe that fields
works fundamentally differently than fields_for
, then I am not sure there is much value for the new tests in this file.
test/bootstrap_form_test.rb
Outdated
if Gem::Version.new(::Rails::VERSION::STRING).release >= Gem::Version.new('5.1.0') | ||
# TODO: Could argue that we should test without `local: true` | ||
assert_equivalent_xml remove_default_ids_for_rails_5_1(expected.gsub(/ class="new_user" id="new_user"/, "")), | ||
bootstrap_form_with(model: @user, local: true) { |f| nil } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is really the only test we need for this PR. But I would split it into 2 tests: one for Rails 5.1, and a second for Rails 5.2+. I prefer it be written as two separate, new tests (i.e. not bundled under test "default-style forms"
). And they should each have their own expected HTML rather than mutating a single expectation with remove_default_ids_for_rails_5_1
. I believe repeating the HTML makes it much more explicit as to what is being tested and what is expected, which is very important value for tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'll do that. (And see my next comment.)
Removed unneeded documentation. Moved `bootstrap_form_with` to after `bootstrap_form_for`.
Thanks! I know this PR has been a lot of work so it is great to finally hit the merge button. I am going to squash it down to one commit and then merge. |
Thanks. It was a great learning experience for me. I really appreciate your help and patience with me while I ground away on this. |
* has-error is now has-danger * inputs with errors should have form-control-feedback * control-label is now form-control-label * btn-default is now btn-secondary * form-horizontal is no longer a required class * input field should have form-control-danger on error * checkbox is now form-check * checkbox input should have form-check-input * non inline checkbox labels should have form-check-label * Support :prepend and :append for the `select` helper (bootstrap-ruby#327) * Support :prepend and :append for the `select` helper Fixes bootstrap-ruby#147 * Bootstrap 4 has renamed `control-label` to `form-control-label` * `form_with` mostly working. The main changes were around the fact that `form_with` doesn't automatically add class and id attributes in many places that the other form builders did. Added a `for:` to the label options if an ID was specified for the input element, so that the label would get the correct value for the `for` attribute. Sub-classed the form builder to override methods to make `form_with` work without the default Rails-generated DOM IDs. * Make it parse under Ruby 1.9.2 The `bootstrap_form_with` helper uses Ruby 2+ syntax. I put a test for the Rails version, so the helper is only parse if running Rails 5.1+. * Try another way to fix Ruby 1.9.2 parse problem. * Try Ruby 1.9.2 syntax yet again. * Close, but going to try keying on Rails ID generation. * Using the underlying option for id generation works. * Use fields instead of fields_for. * Finally remove FormBuilderFormWith. * Remove some unnecessary diffs. Remove confusing comment. Remove some more unnecessary diffs. * Fix select test case for :prepend, :append. * Fix test case that hadn't been converted to form_with. * Documentation tests. Rails 5.2 not tested yet. * Fix out-of-date HTML in test case. * Uncomment and fix Rails 5.1 collection_radio_button tests. * Fix README to remove false statements about 5.2. * heredoc * bootstrap_form_with_test working with 5.1 and 5.2. * Handle Rails 5.1 and 5.2+. * Use heredoc.strip. * Comments and more heredoc formatting. * Partially updated test cases. * Don't add class="" to label if no classes specified. * Intermediate check-in. * Intermediate. * Intermediate. * Intermediate. * Most of custom IDs working. * Uncomment test cases. * Resolve conflicts. * Saving work with tests red and debugging. * Commit before saving to future branch. * Delete redundant test files. * Remove puts and TODOs. * Tests passing up to Rails 5.1. * Some tests for form_with. All pass. * Documentation tested. * Update Rails 5.1 examples in documentation. * Pin minitest to exactly 5.10.1 for Rails 5.0. * Fence off one form_with test. * Add tests for fields method. Pass when they shouldn't. * Go back to using minitest 5.10.3 to do bisect. * Test only form_for in one case. The time zone text strings have an "&" in them. When it's converted to XML and then back to a string, the "&" gets lost. * Test and show that bootstrap_form fields helper not needed * Remove unwanted tests. * Feedback from review. Removed unneeded documentation. Moved `bootstrap_form_with` to after `bootstrap_form_for`. * Minimize test cases. * Fix mistaken commit of version. * Remove code per review. * Remove duplicate CHANGELOG entry
This PR adds a new helper bootstrap_form_with to support the Rails 5.1 form_with helper (#326).
This PR introduces a new helper
bootstrap_form_with
that functions in a very similar way tobootstrap_form_for
andbootstrap_form_tag
. The user can choose to use whichever helper for a given file, although they must be using Rails 5.1 to usebootstrap_form_with
, because it calls Rails'form_with
. Rails 5.0 is still supported.I would like to continue to improve the test coverage, but I believe it's good enough for people to start experimenting with.
The code changes to the actual helpers are not extensive, but testing is a challenge.
form_with
adds to the variety of expected outputs that our tests have to handle. Some examples:form_with
does submits via unobtrusive Javascript, soform
tags are marked withdata-remote="true"
.https://m.patrikonrails.com/rails-5-1s-form-with-vs-old-form-helpers-3a5f72a8c78a is an easy-to-read summary of differences between
form_for
andform_with
.Given the variety of expected outputs from different combinations of versions and helpers (
form_for
vs.form_with
), it was decided to make this PR do the minimum to addbootstrap_form_with
. Additional testing may be added in future PRs.Fixes #326.