bootstrap_form 5.1.0 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +21 -8
  3. data/.gitignore +4 -2
  4. data/.rubocop.yml +2 -1
  5. data/.yarnrc +5 -0
  6. data/CHANGELOG.md +13 -3
  7. data/CONTRIBUTING.md +101 -14
  8. data/Dangerfile +4 -4
  9. data/Dockerfile +5 -5
  10. data/Gemfile +5 -21
  11. data/README.md +108 -42
  12. data/RELEASING.md +12 -1
  13. data/Rakefile +7 -6
  14. data/bootstrap_form.gemspec +6 -8
  15. data/docker-compose.yml +6 -24
  16. data/gemfiles/6.0.gemfile +1 -1
  17. data/gemfiles/6.1.gemfile +1 -1
  18. data/gemfiles/7.0.gemfile +2 -3
  19. data/gemfiles/common.gemfile +28 -0
  20. data/gemfiles/edge.gemfile +3 -2
  21. data/lib/bootstrap_form/components/labels.rb +3 -9
  22. data/lib/bootstrap_form/components/validation.rb +36 -19
  23. data/lib/bootstrap_form/form_builder.rb +4 -1
  24. data/lib/bootstrap_form/form_group.rb +9 -6
  25. data/lib/bootstrap_form/form_group_builder.rb +10 -7
  26. data/lib/bootstrap_form/helpers/bootstrap.rb +7 -8
  27. data/lib/bootstrap_form/helpers/field.rb +26 -0
  28. data/lib/bootstrap_form/helpers.rb +1 -0
  29. data/lib/bootstrap_form/inputs/base.rb +2 -2
  30. data/lib/bootstrap_form/inputs/check_box.rb +22 -6
  31. data/lib/bootstrap_form/inputs/radio_button.rb +3 -3
  32. data/lib/bootstrap_form/inputs/range_field.rb +1 -1
  33. data/lib/bootstrap_form/inputs.rb +1 -1
  34. data/lib/bootstrap_form/version.rb +2 -1
  35. data/lib/bootstrap_form.rb +1 -1
  36. metadata +14 -146
  37. data/demo/.postcssrc.yml +0 -3
  38. data/demo/.ruby-version +0 -1
  39. data/demo/Gemfile +0 -80
  40. data/demo/Gemfile.lock +0 -261
  41. data/demo/Procfile.dev +0 -2
  42. data/demo/README.md +0 -17
  43. data/demo/Rakefile +0 -6
  44. data/demo/app/assets/builds/.keep +0 -0
  45. data/demo/app/assets/builds/application.js.LICENSE.txt +0 -9
  46. data/demo/app/assets/config/manifest.js +0 -2
  47. data/demo/app/assets/stylesheets/actiontext.css +0 -31
  48. data/demo/app/assets/stylesheets/actiontext.scss +0 -38
  49. data/demo/app/assets/stylesheets/application.scss +0 -1
  50. data/demo/app/controllers/application_controller.rb +0 -2
  51. data/demo/app/controllers/bootstrap_controller.rb +0 -29
  52. data/demo/app/controllers/users_controller.rb +0 -9
  53. data/demo/app/helpers/bootstrap_helper.rb +0 -27
  54. data/demo/app/javascript/application.js +0 -3
  55. data/demo/app/javascript/channels/consumer.js +0 -6
  56. data/demo/app/javascript/channels/index.js +0 -5
  57. data/demo/app/javascript/packs/application.js +0 -11
  58. data/demo/app/models/address.rb +0 -3
  59. data/demo/app/models/application_record.rb +0 -3
  60. data/demo/app/models/faux_user.rb +0 -9
  61. data/demo/app/models/skill.rb +0 -15
  62. data/demo/app/models/super_user.rb +0 -2
  63. data/demo/app/models/user.rb +0 -25
  64. data/demo/app/views/active_storage/blobs/_blob.html.erb +0 -14
  65. data/demo/app/views/bootstrap/form.html.erb +0 -67
  66. data/demo/app/views/layouts/action_text/contents/_content.html.erb +0 -3
  67. data/demo/app/views/layouts/application.html.erb +0 -76
  68. data/demo/bin/bundle +0 -3
  69. data/demo/bin/dev +0 -9
  70. data/demo/bin/rails +0 -4
  71. data/demo/bin/rake +0 -4
  72. data/demo/bin/setup +0 -36
  73. data/demo/bin/update +0 -31
  74. data/demo/bin/webpack +0 -15
  75. data/demo/bin/webpack-dev-server +0 -15
  76. data/demo/bin/yarn +0 -11
  77. data/demo/config/application.rb +0 -21
  78. data/demo/config/boot.rb +0 -5
  79. data/demo/config/database.yml +0 -21
  80. data/demo/config/environment.rb +0 -5
  81. data/demo/config/environments/development.rb +0 -60
  82. data/demo/config/environments/production.rb +0 -48
  83. data/demo/config/environments/test.rb +0 -46
  84. data/demo/config/initializers/application_controller_renderer.rb +0 -8
  85. data/demo/config/initializers/backtrace_silencers.rb +0 -7
  86. data/demo/config/initializers/cookies_serializer.rb +0 -5
  87. data/demo/config/initializers/filter_parameter_logging.rb +0 -4
  88. data/demo/config/initializers/inflections.rb +0 -16
  89. data/demo/config/initializers/mime_types.rb +0 -4
  90. data/demo/config/initializers/wrap_parameters.rb +0 -14
  91. data/demo/config/locales/en.yml +0 -33
  92. data/demo/config/puma.rb +0 -56
  93. data/demo/config/routes.rb +0 -6
  94. data/demo/config/spring.rb +0 -6
  95. data/demo/config/storage.yml +0 -35
  96. data/demo/config/webpack/development.js +0 -5
  97. data/demo/config/webpack/environment.js +0 -3
  98. data/demo/config/webpack/production.js +0 -5
  99. data/demo/config/webpack/test.js +0 -5
  100. data/demo/config/webpacker.yml +0 -92
  101. data/demo/config.ru +0 -5
  102. data/demo/db/schema.rb +0 -84
  103. data/demo/doc/screenshots/bootstrap/index/00_horizontal_form.png +0 -0
  104. data/demo/doc/screenshots/bootstrap/index/01_with_validation_error.png +0 -0
  105. data/demo/doc/screenshots/bootstrap/index/02_inline_form.png +0 -0
  106. data/demo/doc/screenshots/bootstrap/index/03_simple_action_text_example.png +0 -0
  107. data/demo/doc/screenshots/bootstrap/index/04_floating_labels.png +0 -0
  108. data/demo/doc/screenshots/bootstrap/readme/00_example.png +0 -0
  109. data/demo/doc/screenshots/bootstrap/readme/01_example.png +0 -0
  110. data/demo/doc/screenshots/bootstrap/readme/02_example.png +0 -0
  111. data/demo/doc/screenshots/bootstrap/readme/03_example.png +0 -0
  112. data/demo/doc/screenshots/bootstrap/readme/04_example.png +0 -0
  113. data/demo/doc/screenshots/bootstrap/readme/05_example.png +0 -0
  114. data/demo/doc/screenshots/bootstrap/readme/06_example.png +0 -0
  115. data/demo/doc/screenshots/bootstrap/readme/07_example.png +0 -0
  116. data/demo/doc/screenshots/bootstrap/readme/08_example.png +0 -0
  117. data/demo/doc/screenshots/bootstrap/readme/09_example.png +0 -0
  118. data/demo/doc/screenshots/bootstrap/readme/10_example.png +0 -0
  119. data/demo/doc/screenshots/bootstrap/readme/11_example.png +0 -0
  120. data/demo/doc/screenshots/bootstrap/readme/12_example.png +0 -0
  121. data/demo/doc/screenshots/bootstrap/readme/13_example.png +0 -0
  122. data/demo/doc/screenshots/bootstrap/readme/14_example.png +0 -0
  123. data/demo/doc/screenshots/bootstrap/readme/15_example.png +0 -0
  124. data/demo/doc/screenshots/bootstrap/readme/16_example.png +0 -0
  125. data/demo/doc/screenshots/bootstrap/readme/17_example.png +0 -0
  126. data/demo/doc/screenshots/bootstrap/readme/18_example.png +0 -0
  127. data/demo/doc/screenshots/bootstrap/readme/19_example.png +0 -0
  128. data/demo/doc/screenshots/bootstrap/readme/20_example.png +0 -0
  129. data/demo/doc/screenshots/bootstrap/readme/21_example.png +0 -0
  130. data/demo/doc/screenshots/bootstrap/readme/22_example.png +0 -0
  131. data/demo/doc/screenshots/bootstrap/readme/23_example.png +0 -0
  132. data/demo/doc/screenshots/bootstrap/readme/24_example.png +0 -0
  133. data/demo/doc/screenshots/bootstrap/readme/25_example.png +0 -0
  134. data/demo/doc/screenshots/bootstrap/readme/26_example.png +0 -0
  135. data/demo/doc/screenshots/bootstrap/readme/27_example.png +0 -0
  136. data/demo/doc/screenshots/bootstrap/readme/28_example.png +0 -0
  137. data/demo/doc/screenshots/bootstrap/readme/29_example.png +0 -0
  138. data/demo/doc/screenshots/bootstrap/readme/30_example.png +0 -0
  139. data/demo/doc/screenshots/bootstrap/readme/31_example.png +0 -0
  140. data/demo/doc/screenshots/bootstrap/readme/32_example.png +0 -0
  141. data/demo/doc/screenshots/bootstrap/readme/33_example.png +0 -0
  142. data/demo/doc/screenshots/bootstrap/readme/34_example.png +0 -0
  143. data/demo/doc/screenshots/bootstrap/readme/35_example.png +0 -0
  144. data/demo/doc/screenshots/bootstrap/readme/36_example.png +0 -0
  145. data/demo/doc/screenshots/bootstrap/readme/37_example.png +0 -0
  146. data/demo/doc/screenshots/bootstrap/readme/38_example.png +0 -0
  147. data/demo/doc/screenshots/bootstrap/readme/39_example.png +0 -0
  148. data/demo/doc/screenshots/bootstrap/readme/40_example.png +0 -0
  149. data/demo/doc/screenshots/bootstrap/readme/41_example.png +0 -0
  150. data/demo/doc/screenshots/bootstrap/readme/42_example.png +0 -0
  151. data/demo/doc/screenshots/bootstrap/readme/43_example.png +0 -0
  152. data/demo/doc/screenshots/bootstrap/readme/44_example.png +0 -0
  153. data/demo/doc/screenshots/bootstrap/readme/45_example.png +0 -0
  154. data/demo/doc/screenshots/bootstrap/readme/46_example.png +0 -0
  155. data/demo/doc/screenshots/bootstrap/readme/47_example.png +0 -0
  156. data/demo/doc/screenshots/bootstrap/readme/48_example.png +0 -0
  157. data/demo/doc/screenshots/bootstrap/readme/49_example.png +0 -0
  158. data/demo/doc/screenshots/bootstrap/readme/50_example.png +0 -0
  159. data/demo/log/.keep +0 -0
  160. data/demo/package.json +0 -21
  161. data/demo/public/favicon.ico +0 -0
  162. data/demo/test/application_system_test_case.rb +0 -8
  163. data/demo/test/controllers/bootstrap_controller_test.rb +0 -8
  164. data/demo/test/controllers/users_controller_test.rb +0 -13
  165. data/demo/test/fixtures/action_text/rich_texts.yml +0 -4
  166. data/demo/test/fixtures/users.yml +0 -2
  167. data/demo/test/system/bootstrap_test.rb +0 -84
  168. data/demo/test/test_helper.rb +0 -10
  169. data/demo/webpack.config.js +0 -20
  170. data/demo/yarn.lock +0 -7176
  171. data/gemfiles/5.2.gemfile +0 -4
data/README.md CHANGED
@@ -25,8 +25,8 @@ Some other nice things that `bootstrap_form` does for you are:
25
25
 
26
26
  `bootstrap_form` supports at a minimum the currently supported versions of Ruby and Rails:
27
27
 
28
- * Ruby 2.5+
29
- * Rails 5.2+
28
+ * Ruby 3.0+ (https://www.ruby-lang.org/en/downloads/branches/)
29
+ * Rails 6.0+ (https://guides.rubyonrails.org/maintenance_policy.html)
30
30
  * Bootstrap 5.0+
31
31
 
32
32
  ## Installation
@@ -42,7 +42,7 @@ And follow the remaining instructions in the [official bootstrap installation gu
42
42
  Add the `bootstrap_form` gem to your `Gemfile`:
43
43
 
44
44
  ```ruby
45
- gem "bootstrap_form", "~> 5.1"
45
+ gem "bootstrap_form", "~> 5.2"
46
46
  ```
47
47
 
48
48
  Then:
@@ -84,7 +84,7 @@ This generates the following HTML:
84
84
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
85
85
  <div class="mb-3">
86
86
  <label class="form-label required" for="user_email">Email</label>
87
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
87
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
88
88
  </div>
89
89
  <div class="mb-3">
90
90
  <label class="form-label" for="user_password">Password</label>
@@ -125,8 +125,6 @@ This generates:
125
125
 
126
126
  ### bootstrap_form_with
127
127
 
128
- 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 behaviour is corrected in Rails 5.2.
129
-
130
128
  To get started, just use the `bootstrap_form_with` helper in place of `form_with`. Here's an example:
131
129
 
132
130
  ![Example 2](demo/doc/screenshots/bootstrap/readme/02_example.png "Example 2")
@@ -145,7 +143,7 @@ This generates:
145
143
  <form accept-charset="UTF-8" action="/users" method="post">
146
144
  <div class="mb-3">
147
145
  <label class="form-label required" for="user_email">Email</label>
148
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
146
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
149
147
  </div>
150
148
  <div class="mb-3">
151
149
  <label class="form-label" for="user_password">Password</label>
@@ -200,7 +198,7 @@ date_field password_field time_field
200
198
  date_select phone_field time_select
201
199
  datetime_field radio_button time_zone_select
202
200
  datetime_local_field range_field url_field
203
- datetime_select rich_text_area (Rails 6+) week_field
201
+ datetime_select rich_text_area week_field
204
202
  ```
205
203
 
206
204
  By default, the helpers generate a `label` tag, and an `input`, `select`, or `textarea` tag, by calling the Rails `label` helper, and then the Rails helper with the same name as the `bootstrap_form` helper.
@@ -278,7 +276,7 @@ This generates:
278
276
  ```html
279
277
  <div class="mb-3">
280
278
  <label class="form-label custom-class required" for="user_email">Email</label>
281
- <input class="form-control" id="user_email" name="user[email]" type="text" value="steve@example.com">
279
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="text" value="steve@example.com">
282
280
  </div>
283
281
  ```
284
282
 
@@ -294,7 +292,7 @@ This generates:
294
292
  ```html
295
293
  <div class="mb-3">
296
294
  <label class="form-label visually-hidden required" for="user_email">Email</label>
297
- <input class="form-control" id="user_email" name="user[email]" placeholder="Email" type="text" value="steve@example.com">
295
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" placeholder="Email" required="required" type="text" value="steve@example.com">
298
296
  </div>
299
297
  ```
300
298
 
@@ -312,7 +310,7 @@ This generates:
312
310
  ```html
313
311
  <div class="mb-3">
314
312
  <label class="form-label required" for="user_email">Email</label>
315
- <input class="custom-class" id="user_email" name="user[email]" type="text" value="steve@example.com">
313
+ <input aria-required="true" class="custom-class" id="user_email" name="user[email]" required="required" type="text" value="steve@example.com">
316
314
  </div>
317
315
  ```
318
316
 
@@ -438,7 +436,7 @@ This generates:
438
436
  <div class="mb-3">
439
437
  <label class="form-label required" for="user_email">Email</label>
440
438
  <div class="input-group input-group-lg">
441
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
439
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
442
440
  <input class="btn btn-primary" data-disable-with="Subscribe" name="commit" type="submit" value="Subscribe">
443
441
  </div>
444
442
  </div>
@@ -503,7 +501,7 @@ Generated HTML:
503
501
 
504
502
  ```html
505
503
  <div class="mb-3">
506
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
504
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
507
505
  </div>
508
506
  ```
509
507
 
@@ -753,7 +751,7 @@ This generates:
753
751
  ```html
754
752
  <div class="mb-3">
755
753
  <label class="form-label" for="user_excellence">Excellence</label>
756
- <input class="form-control" id="user_excellence" name="user[excellence]" type="range">
754
+ <input class="form-range" id="user_excellence" name="user[excellence]" type="range">
757
755
  </div>
758
756
  ```
759
757
 
@@ -771,7 +769,7 @@ This generates:
771
769
  ```html
772
770
  <div class="mb-3">
773
771
  <label class="form-label required" for="user_email">Email</label>
774
- <input class="form-control-plaintext" id="user_email" name="user[email]" readonly type="text" value="steve@example.com">
772
+ <input aria-required="true" class="form-control-plaintext" id="user_email" name="user[email]" readonly required="required" type="text" value="steve@example.com">
775
773
  </div>
776
774
  ```
777
775
 
@@ -791,7 +789,7 @@ This generates:
791
789
  <div class="mb-3 row">
792
790
  <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
793
791
  <div class="col-sm-10">
794
- <input class="form-control-plaintext" id="user_email" name="user[email]" readonly type="text" value="steve@example.com">
792
+ <input aria-required="true" class="form-control-plaintext" id="user_email" name="user[email]" readonly required="required" type="text" value="steve@example.com">
795
793
  </div>
796
794
  </div>
797
795
  </form>
@@ -946,8 +944,6 @@ will be rendered as
946
944
 
947
945
  ## Rich Text Areas AKA Trix Editor
948
946
 
949
- If you're using Rails 6, `bootstrap_form` supports the `rich_text_area` helper.
950
-
951
947
  ![Example 34](demo/doc/screenshots/bootstrap/readme/34_example.png "Example 34")
952
948
  ```erb
953
949
  <%= f.rich_text_area(:life_story) %>
@@ -1054,7 +1050,7 @@ This generates:
1054
1050
  <form accept-charset="UTF-8" action="/users" class="new_user row row-cols-auto g-3 align-items-center" id="new_user" method="post">
1055
1051
  <div class="col">
1056
1052
  <label class="form-label visually-hidden mr-sm-2 required" for="user_email">Email</label>
1057
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
1053
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1058
1054
  </div>
1059
1055
  <div class="col">
1060
1056
  <label class="form-label visually-hidden mr-sm-2" for="user_password">Password</label>
@@ -1116,7 +1112,7 @@ This generates:
1116
1112
  <div class="mb-3 row">
1117
1113
  <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
1118
1114
  <div class="col-sm-10">
1119
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
1115
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1120
1116
  </div>
1121
1117
  </div>
1122
1118
  <div class="mb-3 row">
@@ -1134,7 +1130,7 @@ This generates:
1134
1130
  </div>
1135
1131
  </div>
1136
1132
  </div>
1137
-
1133
+
1138
1134
  <div class="mb-3 row">
1139
1135
  <div class="col-sm-10 offset-sm-2">
1140
1136
  <input class="btn btn-secondary" data-disable-with="Create User" name="commit" type="submit" value="Create User">
@@ -1163,7 +1159,7 @@ This generates:
1163
1159
  <div class="mb-3 row">
1164
1160
  <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
1165
1161
  <div class="col-sm-10">
1166
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
1162
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1167
1163
  </div>
1168
1164
  </div>
1169
1165
  <div class="mb-3 row">
@@ -1220,7 +1216,7 @@ This generates:
1220
1216
  <div class="mb-3 row">
1221
1217
  <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
1222
1218
  <div class="col-sm-10">
1223
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
1219
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1224
1220
  </div>
1225
1221
  </div>
1226
1222
  <div class="mb-3 row">
@@ -1260,7 +1256,7 @@ This generates:
1260
1256
  <div class="mb-3 row">
1261
1257
  <label class="form-label col-form-label col-sm-2 required" for="user_email">Email</label>
1262
1258
  <div class="col-sm-10">
1263
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
1259
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1264
1260
  </div>
1265
1261
  </div>
1266
1262
  <div class="mb-3">
@@ -1301,7 +1297,7 @@ This generates:
1301
1297
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1302
1298
  <div class="mb-3">
1303
1299
  <label class="form-label required" for="user_email">Email</label>
1304
- <input class="form-control" id="user_email" name="user[email]" type="email" value="steve@example.com">
1300
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" required="required" type="email" value="steve@example.com">
1305
1301
  </div>
1306
1302
  <div class="mb-3">
1307
1303
  <label class="form-label" for="user_password">Password</label>
@@ -1337,7 +1333,7 @@ This generates:
1337
1333
  ```html
1338
1334
  <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1339
1335
  <div class="mb-3 form-floating">
1340
- <input class="form-control" id="user_email" name="user[email]" placeholder="Email" type="email" value="steve@example.com">
1336
+ <input aria-required="true" class="form-control" id="user_email" name="user[email]" placeholder="Email" required="required" type="email" value="steve@example.com">
1341
1337
  <label class="form-label required" for="user_email">Email</label>
1342
1338
  </div>
1343
1339
  <div class="mb-3 form-floating">
@@ -1369,18 +1365,29 @@ Rails normally wraps fields with validation errors in a `div.field_with_errors`,
1369
1365
  By default, fields that have validation errors will be outlined in red and the
1370
1366
  error will be displayed below the field. Here's an example:
1371
1367
 
1368
+ ![Example 44](demo/doc/screenshots/bootstrap/readme/44_example.png "Example 44")
1369
+ ```erb
1370
+ <%= bootstrap_form_for(@user_with_error) do |f| %>
1371
+ <%= f.email_field :email %>
1372
+ <% end %>
1373
+ ```
1374
+
1375
+ Generated HTML:
1376
+
1372
1377
  ```html
1373
- <div class="mb-3">
1374
- <label class="form-label form-control-label" for="user_email">Email</label>
1375
- <input class="form-control is-invalid" id="user_email" name="user[email]" type="email" value="">
1376
- <small class="invalid-feedback">can't be blank</small>
1377
- </div>
1378
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1379
+ <div class="mb-3">
1380
+ <label class="form-label required" for="user_email">Email</label>
1381
+ <input aria-required="true" class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
1382
+ <div class="invalid-feedback">is invalid</div>
1383
+ </div>
1384
+ </form>
1378
1385
  ```
1379
1386
 
1380
1387
  You can turn off inline errors for the entire form like this:
1381
1388
 
1382
1389
  ```erb
1383
- <%= bootstrap_form_for(@user, inline_errors: false) do |f| %>
1390
+ <%= bootstrap_form_for(@user_with_error, inline_errors: false) do |f| %>
1384
1391
  ...
1385
1392
  <% end %>
1386
1393
  ```
@@ -1390,12 +1397,24 @@ You can turn off inline errors for the entire form like this:
1390
1397
  You can also display validation errors in the field's label; just turn
1391
1398
  on the `:label_errors` option. Here's an example:
1392
1399
 
1400
+ ![Example 45](demo/doc/screenshots/bootstrap/readme/45_example.png "Example 45")
1393
1401
  ```erb
1394
- <%= bootstrap_form_for(@user, label_errors: true) do |f| %>
1395
- ...
1402
+ <%= bootstrap_form_for(@user_with_error, label_errors: true) do |f| %>
1403
+ <%= f.email_field :email %>
1396
1404
  <% end %>
1397
1405
  ```
1398
1406
 
1407
+ Generated HTML:
1408
+
1409
+ ```html
1410
+ <form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post">
1411
+ <div class="mb-3">
1412
+ <label class="form-label required text-danger" for="user_email">Email is invalid</label>
1413
+ <input aria-required="true" class="form-control is-invalid" id="user_email" name="user[email]" required="required" type="email" value="steve.example.com">
1414
+ </div>
1415
+ </form>
1416
+ ```
1417
+
1399
1418
  By default, turning on `:label_errors` will also turn off
1400
1419
  `:inline_errors`. If you want both turned on, you can do that too:
1401
1420
 
@@ -1411,7 +1430,7 @@ To display an error message with an error summary, you can use the
1411
1430
  `alert_message` helper. This won't output anything unless a model validation
1412
1431
  has failed.
1413
1432
 
1414
- ![Example 44](demo/doc/screenshots/bootstrap/readme/44_example.png "Example 44")
1433
+ ![Example 46](demo/doc/screenshots/bootstrap/readme/46_example.png "Example 46")
1415
1434
  ```erb
1416
1435
  <%= bootstrap_form_for @user_with_error do |f| %>
1417
1436
  <%= f.alert_message "Please fix the errors below." %>
@@ -1434,7 +1453,7 @@ Which outputs:
1434
1453
 
1435
1454
  You can turn off the error summary like this:
1436
1455
 
1437
- ![Example 45](demo/doc/screenshots/bootstrap/readme/45_example.png "Example 45")
1456
+ ![Example 47](demo/doc/screenshots/bootstrap/readme/47_example.png "Example 47")
1438
1457
  ```erb
1439
1458
  <%= bootstrap_form_for @user_with_error do |f| %>
1440
1459
  <%= f.alert_message "Please fix the errors below.", error_summary: false %>
@@ -1451,7 +1470,7 @@ This generates:
1451
1470
 
1452
1471
  To output a simple unordered list of errors, use the `error_summary` helper.
1453
1472
 
1454
- ![Example 46](demo/doc/screenshots/bootstrap/readme/46_example.png "Example 46")
1473
+ ![Example 48](demo/doc/screenshots/bootstrap/readme/48_example.png "Example 48")
1455
1474
  ```erb
1456
1475
  <%= bootstrap_form_for @user_with_error do |f| %>
1457
1476
  <%= f.error_summary %>
@@ -1473,7 +1492,7 @@ Which outputs:
1473
1492
 
1474
1493
  If you want to display a custom inline error for a specific attribute not represented by a form field, use the `errors_on` helper.
1475
1494
 
1476
- ![Example 47](demo/doc/screenshots/bootstrap/readme/47_example.png "Example 47")
1495
+ ![Example 49](demo/doc/screenshots/bootstrap/readme/49_example.png "Example 49")
1477
1496
  ```erb
1478
1497
  <%= bootstrap_form_for @user_with_error do |f| %>
1479
1498
  <%= f.errors_on :email %>
@@ -1490,7 +1509,7 @@ Which outputs:
1490
1509
 
1491
1510
  You can hide the attribute name like this:
1492
1511
 
1493
- ![Example 48](demo/doc/screenshots/bootstrap/readme/48_example.png "Example 48")
1512
+ ![Example 50](demo/doc/screenshots/bootstrap/readme/50_example.png "Example 50")
1494
1513
  ```erb
1495
1514
  <%= bootstrap_form_for @user_with_error do |f| %>
1496
1515
  <%= f.errors_on :email, hide_attribute_name: true %>
@@ -1507,7 +1526,7 @@ Which outputs:
1507
1526
 
1508
1527
  You can also use a custom class for the wrapping div, like this:
1509
1528
 
1510
- ![Example 49](demo/doc/screenshots/bootstrap/readme/49_example.png "Example 49")
1529
+ ![Example 51](demo/doc/screenshots/bootstrap/readme/51_example.png "Example 51")
1511
1530
  ```erb
1512
1531
  <%= bootstrap_form_for @user_with_error do |f| %>
1513
1532
  <%= f.errors_on :email, custom_class: 'custom-error' %>
@@ -1542,7 +1561,7 @@ ActiveModel::Validations::PresenceValidator.
1542
1561
 
1543
1562
  In cases where this behaviour is undesirable, use the `required` option to force the class to be present or absent:
1544
1563
 
1545
- ![Example 50](demo/doc/screenshots/bootstrap/readme/50_example.png "Example 50")
1564
+ ![Example 52](demo/doc/screenshots/bootstrap/readme/52_example.png "Example 52")
1546
1565
  ```erb
1547
1566
  <%= f.password_field :login, label: "New Username", required: true %>
1548
1567
  <%= f.password_field :password, label: "New Password", required: false %>
@@ -1553,7 +1572,7 @@ This generates:
1553
1572
  ```html
1554
1573
  <div class="mb-3">
1555
1574
  <label class="form-label required" for="user_login">New Username</label>
1556
- <input class="form-control" id="user_login" name="user[login]" required="required" type="password">
1575
+ <input aria-required="true" class="form-control" id="user_login" name="user[login]" required="required" type="password">
1557
1576
  </div>
1558
1577
  <div class="mb-3">
1559
1578
  <label class="form-label" for="user_password">New Password</label>
@@ -1561,6 +1580,53 @@ This generates:
1561
1580
  </div>
1562
1581
  ```
1563
1582
 
1583
+ ### Required belongs_to associations
1584
+
1585
+ Adding a form control for a `belongs_to` field will automatically pick up the associated presence validator.
1586
+
1587
+ ![Example 53](demo/doc/screenshots/bootstrap/readme/53_example.png "Example 53")
1588
+ ```erb
1589
+ <%= bootstrap_form_for(@address, url: '/address') do |f| %>
1590
+ <%= f.collection_select :user_id, @users, :id, :email, include_blank: "Select a value" %>
1591
+ <%= f.text_field :street %>
1592
+ <%= f.text_field :city %>
1593
+ <%= f.text_field :state %>
1594
+ <%= f.text_field :zip_code %>
1595
+ <%= f.submit "Save" %>
1596
+ <% end %>
1597
+ ```
1598
+
1599
+ Generated HTML:
1600
+
1601
+ ```html
1602
+ <form accept-charset="UTF-8" action="/address" class="new_address" id="new_address_1" method="post">
1603
+ <div class="mb-3">
1604
+ <label class="form-label required" for="address_user_id">User</label>
1605
+ <select class="form-select" id="address_user_id" name="address[user_id]">
1606
+ <option value="">Select a value</option>
1607
+ <option value="">steve@example.com</option>
1608
+ </select>
1609
+ </div>
1610
+ <div class="mb-3">
1611
+ <label class="form-label" for="address_street">Street</label>
1612
+ <input class="form-control" id="address_street" name="address[street]" type="text" value="Foo">
1613
+ </div>
1614
+ <div class="mb-3">
1615
+ <label class="form-label" for="address_city">City</label>
1616
+ <input class="form-control" id="address_city" name="address[city]" type="text">
1617
+ </div>
1618
+ <div class="mb-3">
1619
+ <label class="form-label" for="address_state">State</label>
1620
+ <input class="form-control" id="address_state" name="address[state]" type="text">
1621
+ </div>
1622
+ <div class="mb-3">
1623
+ <label class="form-label" for="address_zip_code">Zip code</label>
1624
+ <input class="form-control" id="address_zip_code" name="address[zip_code]" type="text">
1625
+ </div>
1626
+ <input class="btn btn-secondary" data-disable-with="Save" name="commit" type="submit" value="Save">
1627
+ </form>
1628
+ ```
1629
+
1564
1630
  ## Internationalization
1565
1631
 
1566
1632
  bootstrap_form follows standard rails conventions so it's i18n-ready. See more
data/RELEASING.md CHANGED
@@ -11,7 +11,18 @@ Follow these steps to release a new version of bootstrap_form to rubygems.org.
11
11
  ## How to release
12
12
 
13
13
  1. Run `BUNDLE_GEMFILE=gemfiles/7.0.gemfile bundle update` to make sure that you have all the gems necessary for testing and releasing.
14
- 2. **Ensure the tests are passing by running `BUNDLE_GEMFILE=gemfiles/7.0.gemfile bundle update`.** (Currently this step shows a lot of warnings about method redefinitions, but otherwise everything must be green before release.)
14
+ 2. **Ensure the tests are passing by running the tests**
15
+
16
+ (There should be no errors or warnings.)
17
+
18
+ BUNDLE_GEMFILE=gemfiles/7.0.gemfile bundle exec rake test
19
+
20
+ 2. **Ensure the demo tests are passing by running**
21
+
22
+ cd demo
23
+ bundle update
24
+ bundle exec rake test:all
25
+
15
26
  3. Determine which would be the correct next version number according to [semver](http://semver.org/).
16
27
  4. Update the version in `./lib/bootstrap_form/version.rb`.
17
28
  5. Update the GitHub diff links at the beginning of `CHANGELOG.md` (The pattern should be obvious when you look at them).
data/Rakefile CHANGED
@@ -17,12 +17,13 @@ end
17
17
 
18
18
  require 'bundler/gem_tasks'
19
19
 
20
- require 'rake/testtask'
20
+ require "minitest/test_task"
21
21
 
22
- Rake::TestTask.new(:test) do |t|
23
- t.libs << 'test'
24
- t.pattern = 'test/**/*_test.rb'
25
- t.verbose = false
22
+ Minitest::TestTask.create(:test) do |t|
23
+ t.libs << "test"
24
+ t.libs << "lib"
25
+ t.warning = false
26
+ t.test_globs = ["test/**/*_test.rb"]
26
27
  end
27
28
 
28
29
  # This automatically updates GitHub Releases whenever we `rake release` the gem
@@ -34,4 +35,4 @@ end
34
35
  desc 'Run RuboCop checks'
35
36
  RuboCop::RakeTask.new(:rubocop)
36
37
 
37
- task default: %i[test rubocop]
38
+ task default: %i[test rubocop:autocorrect]
@@ -3,30 +3,28 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  require "bootstrap_form/version"
5
5
 
6
- REQUIRED_RAILS_VERSION = ">= 5.2".freeze
7
-
8
6
  Gem::Specification.new do |s|
9
7
  s.name = "bootstrap_form"
10
8
  s.version = BootstrapForm::VERSION
11
9
  s.authors = ["Stephen Potenza", "Carlos Lopes"]
12
10
  s.email = ["potenza@gmail.com", "carlos.el.lopes@gmail.com"]
13
11
  s.homepage = "https://github.com/bootstrap-ruby/bootstrap_form"
14
- s.summary = "Rails form builder that makes it easy to style forms using "\
12
+ s.summary = "Rails form builder that makes it easy to style forms using " \
15
13
  "Bootstrap 5"
16
- s.description = "bootstrap_form is a rails form builder that makes it super "\
14
+ s.description = "bootstrap_form is a rails form builder that makes it super " \
17
15
  "easy to create beautiful-looking forms using Bootstrap 5"
18
16
  s.license = "MIT"
19
17
  s.metadata = { "rubygems_mfa_required" => "true" }
20
18
 
21
19
  s.files = `git ls-files -z`.split("\x0").reject do |f|
22
- f.match(%r{^(test)/})
20
+ f.match(%r{^(test)/|^(demo)/})
23
21
  end
24
22
 
25
23
  s.bindir = "exe"
26
24
  s.require_paths = ["lib"]
27
25
 
28
- s.required_ruby_version = ">= 2.7"
26
+ s.required_ruby_version = ">= 3.0"
29
27
 
30
- s.add_dependency("actionpack", REQUIRED_RAILS_VERSION)
31
- s.add_dependency("activemodel", REQUIRED_RAILS_VERSION)
28
+ s.add_dependency("actionpack", BootstrapForm::REQUIRED_RAILS_VERSION)
29
+ s.add_dependency("activemodel", BootstrapForm::REQUIRED_RAILS_VERSION)
32
30
  end
data/docker-compose.yml CHANGED
@@ -5,9 +5,10 @@ services:
5
5
  build:
6
6
  context: .
7
7
  args:
8
- NODE_MAJOR: '12'
9
- YARN_VERSION: '1.22.4'
10
- image: bootstrap-form:0.0.1
8
+ NODE_MAJOR: "12"
9
+ YARN_VERSION: "1.22.4"
10
+ RUBY_VERSION: ${RUBY_VERSION}
11
+ image: bootstrap-form:latest-$RUBY_VERSION
11
12
  tmpfs:
12
13
  - /tmp
13
14
 
@@ -17,15 +18,6 @@ services:
17
18
  tty: true
18
19
  volumes:
19
20
  - .:/app:cached
20
- # - rails_cache:/app/tmp/cache
21
- # - bundle:/app/vendor/bundle
22
- # - node_modules:/app/node_modules
23
- # - packs:/app/public/packs
24
- - /etc/passwd:/etc/passwd:ro
25
- # One or the other of the following lines might be redundant, or one might be
26
- # better than the other.
27
- - ~/.ssh:${HOME}/.ssh
28
- - ${SSH_AUTH_SOCK}:/ssh-agent
29
21
  environment:
30
22
  - SSH_AUTH_SOCK=/ssh-agent
31
23
  - NODE_ENV=development
@@ -34,16 +26,6 @@ services:
34
26
  - WEBPACKER_DEV_SERVER_HOST=webpacker
35
27
  - WEB_CONCURRENCY=1
36
28
  - HISTFILE=/app/.bash_history
29
+ ports:
30
+ - "3000:3000"
37
31
  command: /bin/bash
38
-
39
- # server:
40
- # <<: *shell
41
- # command: sh -c "cd demo/app && bundle exec rails server -b 0.0.0.0"
42
- # ports:
43
- # - '3000:3000'
44
-
45
- # volumes:
46
- # bundle:
47
- # node_modules:
48
- # rails_cache:
49
- # packs:
data/gemfiles/6.0.gemfile CHANGED
@@ -1,4 +1,4 @@
1
- gems = "#{File.dirname __dir__}/Gemfile"
1
+ gems = "#{__dir__}/common.gemfile"
2
2
  eval File.read(gems), binding, gems # rubocop: disable Security/Eval
3
3
 
4
4
  gem "rails", "~> 6.0.0"
data/gemfiles/6.1.gemfile CHANGED
@@ -1,4 +1,4 @@
1
- gems = "#{File.dirname __dir__}/Gemfile"
1
+ gems = "#{__dir__}/common.gemfile"
2
2
  eval File.read(gems), binding, gems # rubocop: disable Security/Eval
3
3
 
4
4
  gem "rails", "~> 6.1.0"
data/gemfiles/7.0.gemfile CHANGED
@@ -1,6 +1,5 @@
1
- gems = "#{File.dirname __dir__}/Gemfile"
1
+ gems = "#{__dir__}/common.gemfile"
2
2
  eval File.read(gems), binding, gems # rubocop: disable Security/Eval
3
3
 
4
- # 7.0.0 has an issue with Ruby 3.1.
5
- # And a test case has an issue with 7.0.1
6
4
  gem "rails", "~> 7.0.2"
5
+ gem "sprockets-rails", require: "sprockets/railtie"
@@ -0,0 +1,28 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec path: File.dirname(__dir__)
4
+
5
+ # To test with different Rails versions, use the files in `./gemfiles`
6
+
7
+ group :development do
8
+ gem "htmlbeautifier"
9
+ gem "puma"
10
+ gem "rubocop-performance", require: false
11
+ gem "rubocop-rails", require: false
12
+ end
13
+
14
+ group :test do
15
+ gem "diffy"
16
+ gem "equivalent-xml"
17
+ gem "mocha"
18
+ gem "sqlite3"
19
+ end
20
+
21
+ group :development, :test do
22
+ gem "debug"
23
+ gem "pry-byebug"
24
+ end
25
+
26
+ group :ci do
27
+ gem "danger"
28
+ end
@@ -1,4 +1,5 @@
1
- gems = "#{File.dirname __dir__}/Gemfile"
1
+ gems = "#{__dir__}/common.gemfile"
2
2
  eval File.read(gems), binding, gems # rubocop: disable Security/Eval
3
3
 
4
- gem "rails", git: "https://github.com/rails/rails.git"
4
+ gem "rails", git: "https://github.com/rails/rails.git", branch: "main"
5
+ gem "sprockets-rails", require: "sprockets/railtie"
@@ -24,14 +24,8 @@ module BootstrapForm
24
24
 
25
25
  def label_classes(name, options, custom_label_col, group_layout)
26
26
  classes = ["form-label", options[:class], label_layout_classes(custom_label_col, group_layout)]
27
-
28
- case options.delete(:required)
29
- when true
30
- classes << "required"
31
- when nil, :default
32
- classes << "required" if required_attribute?(object, name)
33
- end
34
-
27
+ classes << "required" if required_field_options(options, name)[:required]
28
+ options.delete(:required)
35
29
  classes << "text-danger" if label_errors && error?(name)
36
30
  classes.flatten.compact
37
31
  end
@@ -46,7 +40,7 @@ module BootstrapForm
46
40
 
47
41
  def label_text(name, options)
48
42
  if label_errors && error?(name)
49
- (options[:text] || object.class.human_attribute_name(name)).to_s.concat(" #{get_error_messages(name)}")
43
+ (options[:text] || object.class.human_attribute_name(name)).to_s + " #{get_error_messages(name)}"
50
44
  else
51
45
  options[:text] || object&.class.try(:human_attribute_name, name)
52
46
  end