bootstrap_form 5.3.2 → 5.5.0

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer.json +38 -0
  3. data/.github/workflows/ruby.yml +11 -4
  4. data/.gitignore +27 -8
  5. data/.rubocop.yml +5 -6
  6. data/.yarnrc +1 -1
  7. data/CHANGELOG.md +5 -0
  8. data/CONTRIBUTING.md +34 -82
  9. data/DOCKER.md +95 -0
  10. data/Gemfile +5 -1
  11. data/README.md +143 -80
  12. data/RELEASING.md +3 -8
  13. data/Rakefile +23 -0
  14. data/bootstrap_form.gemspec +1 -1
  15. data/compose.yml +36 -0
  16. data/gemfiles/7.2.gemfile +9 -0
  17. data/gemfiles/8.0.gemfile +9 -0
  18. data/gemfiles/8.1.gemfile +9 -0
  19. data/gemfiles/common.gemfile +1 -2
  20. data/gemfiles/edge.gemfile +5 -1
  21. data/lib/bootstrap_form/action_view_extensions/form_helper.rb +6 -6
  22. data/lib/bootstrap_form/components/labels.rb +4 -3
  23. data/lib/bootstrap_form/components/validation.rb +1 -2
  24. data/lib/bootstrap_form/form_builder.rb +16 -8
  25. data/lib/bootstrap_form/form_group.rb +3 -3
  26. data/lib/bootstrap_form/form_group_builder.rb +3 -3
  27. data/lib/bootstrap_form/helpers/bootstrap.rb +15 -12
  28. data/lib/bootstrap_form/inputs/base.rb +15 -6
  29. data/lib/bootstrap_form/inputs/check_box.rb +11 -5
  30. data/lib/bootstrap_form/inputs/collection_check_boxes.rb +2 -8
  31. data/lib/bootstrap_form/inputs/file_field.rb +1 -1
  32. data/lib/bootstrap_form/inputs/range_field.rb +1 -1
  33. data/lib/bootstrap_form/inputs/rich_text_area.rb +3 -1
  34. data/lib/bootstrap_form/inputs/submit.rb +1 -1
  35. data/lib/bootstrap_form/inputs/text_area.rb +2 -0
  36. data/lib/bootstrap_form/version.rb +2 -2
  37. data/lib/bootstrap_form.rb +0 -6
  38. metadata +14 -12
  39. data/Dockerfile +0 -21
  40. data/docker-compose.yml +0 -31
  41. data/gemfiles/6.1.gemfile +0 -4
  42. data/gemfiles/7.0.gemfile +0 -5
data/RELEASING.md CHANGED
@@ -14,20 +14,15 @@ Follow these steps to release a new version of bootstrap_form to rubygems.org.
14
14
  2. Update the version in `./lib/bootstrap_form/version.rb`.
15
15
  3. Make sure that you have all the gems necessary for testing and releasing.
16
16
 
17
- BUNDLE_GEMFILE=gemfiles/7.0.gemfile bundle update
17
+ BUNDLE_GEMFILE=gemfiles/7.2.gemfile bundle update
18
18
 
19
19
  4. **Ensure the tests are passing by running the tests**
20
20
 
21
21
  (There should be no errors or warnings.)
22
22
 
23
- BUNDLE_GEMFILE=gemfiles/7.0.gemfile bundle exec rake test
24
-
25
- 5. **Ensure the demo tests are passing by running**
26
-
27
- cd demo
28
- bundle update
29
23
  bundle exec rake test:all
30
- cd -
24
+
25
+ You will have failures in the system tests unless you're running on Linux. Chrome on each operating system renders slightly differently.
31
26
 
32
27
  6. Update the GitHub diff links at the beginning of `CHANGELOG.md` (The pattern should be obvious when you look at them).
33
28
  7. Update the installation instructions in `README.md` to use the new version.
data/Rakefile CHANGED
@@ -28,3 +28,26 @@ desc 'Run RuboCop checks'
28
28
  RuboCop::RakeTask.new(:rubocop)
29
29
 
30
30
  task default: %i[test rubocop:autocorrect]
31
+
32
+ namespace :test do
33
+ desc "Run tests for all supported Rails versions, with current Ruby version"
34
+ task :all do
35
+ original_gemfile = ENV["BUNDLE_GEMFILE"]
36
+ gemfiles = Dir.glob("gemfiles/*.gemfile").reject { |f| File.basename(f) == "common.gemfile" }
37
+ gemfiles.each do |f|
38
+ ENV["BUNDLE_GEMFILE"] = f
39
+ system("bundle check") || system("bundle install")
40
+ system("bundle exec rake test")
41
+ end
42
+
43
+ original_directory = Dir.pwd
44
+ Dir.chdir("demo")
45
+ ENV.delete("BUNDLE_GEMFILE")
46
+ system("bundle check") || system("bundle install")
47
+ system("bundle exec rake test:all")
48
+
49
+ ensure
50
+ original_gemfile.nil? ? ENV.delete("BUNDLE_GEMFILE") : ENV["BUNDLE_GEMFILE"] = original_gemfile
51
+ Dir.chdir(original_directory) unless original_directory.nil?
52
+ end
53
+ end
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.bindir = "exe"
24
24
  s.require_paths = ["lib"]
25
25
 
26
- s.required_ruby_version = ">= 3.0"
26
+ s.required_ruby_version = ">= 3.2"
27
27
 
28
28
  s.add_dependency("actionpack", BootstrapForm::REQUIRED_RAILS_VERSION)
29
29
  s.add_dependency("activemodel", BootstrapForm::REQUIRED_RAILS_VERSION)
data/compose.yml ADDED
@@ -0,0 +1,36 @@
1
+ # Set up the Selenium container based on the Selenium official:
2
+ # https://github.com/SeleniumHQ/docker-selenium/blob/trunk/docker-compose-v3.yml
3
+ # And:
4
+ # https://medium.com/@retrorubies/chrome-as-a-service-for-rails-testing-b1a45e70fec1
5
+ services:
6
+ web:
7
+ image: lenchoreyes/jade:rails-app-${RUBY_VERSION:-3.3}-sqlite-${DISTRO:-bookworm}
8
+ stdin_open: true
9
+ tty: true
10
+ volumes:
11
+ - .:/app:cached
12
+ environment:
13
+ - HISTFILE=/app/.bash_history
14
+ - SELENIUM_HOST=selenium
15
+ - SELENIUM_PORT=4444
16
+ - TEST_APP_HOST=web
17
+ - TEST_APP_PORT=3001
18
+ ports:
19
+ - "3000"
20
+ - "3001"
21
+ command: /bin/bash
22
+
23
+ selenium:
24
+ image: selenium/standalone-chrome:133.0
25
+ shm_size: 2gb
26
+ logging:
27
+ driver: none
28
+ stdin_open: true
29
+ tty: true
30
+ environment:
31
+ - LANG=en_CA.UTF-8
32
+ - LANGUAGE=en_CA.UTF-8
33
+ - LANG_WHERE=CA
34
+ - LANG_WHICH=en
35
+ ports:
36
+ - "7900"
@@ -0,0 +1,9 @@
1
+ gems = "#{__dir__}/common.gemfile"
2
+ eval File.read(gems), binding, gems # rubocop: disable Security/Eval
3
+
4
+ gem "bigdecimal" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
5
+ gem "drb" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
6
+ gem "mutex_m" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
7
+ gem "rails", "~> 7.2.0"
8
+ gem "sprockets-rails", require: "sprockets/railtie"
9
+ gem "sqlite3"
@@ -0,0 +1,9 @@
1
+ gems = "#{__dir__}/common.gemfile"
2
+ eval File.read(gems), binding, gems # rubocop: disable Security/Eval
3
+
4
+ gem "bigdecimal" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
5
+ gem "drb" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
6
+ gem "mutex_m" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
7
+ gem "propshaft"
8
+ gem "rails", "~> 8.0.1"
9
+ gem "sqlite3"
@@ -0,0 +1,9 @@
1
+ gems = "#{__dir__}/common.gemfile"
2
+ eval File.read(gems), binding, gems # rubocop: disable Security/Eval
3
+
4
+ gem "bigdecimal" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
5
+ gem "drb" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
6
+ gem "mutex_m" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
7
+ gem "propshaft"
8
+ gem "rails", "~> 8.1.0"
9
+ gem "sqlite3"
@@ -15,12 +15,11 @@ group :test do
15
15
  gem "diffy"
16
16
  gem "equivalent-xml"
17
17
  gem "mocha"
18
- gem "sqlite3"
19
18
  end
20
19
 
21
20
  group :development, :test do
22
21
  gem "debug"
23
- gem "pry-byebug"
22
+ gem "ostruct" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.5.0")
24
23
  end
25
24
 
26
25
  group :ci do
@@ -1,5 +1,9 @@
1
1
  gems = "#{__dir__}/common.gemfile"
2
2
  eval File.read(gems), binding, gems # rubocop: disable Security/Eval
3
3
 
4
+ gem "bigdecimal" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
5
+ gem "drb" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
6
+ gem "mutex_m" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0")
7
+ gem "propshaft"
4
8
  gem "rails", git: "https://github.com/rails/rails.git", branch: "main"
5
- gem "sprockets-rails", require: "sprockets/railtie"
9
+ gem "sqlite3"
@@ -33,20 +33,20 @@ module BootstrapForm
33
33
  end
34
34
  end
35
35
 
36
- def bootstrap_form_tag(options={}, &block)
36
+ def bootstrap_form_tag(options={}, &)
37
37
  options[:acts_like_form_tag] = true
38
38
 
39
- bootstrap_form_for("", options, &block)
39
+ bootstrap_form_for("", options, &)
40
40
  end
41
41
 
42
- def bootstrap_fields_for(record_name, record_object=nil, options={}, &block)
42
+ def bootstrap_fields_for(record_name, record_object=nil, options={}, &)
43
43
  options[:builder] = BootstrapForm::FormBuilder
44
- fields_for(record_name, record_object, options, &block)
44
+ fields_for(record_name, record_object, options, &)
45
45
  end
46
46
 
47
- def bootstrap_fields(scope=nil, model: nil, **options, &block)
47
+ def bootstrap_fields(scope=nil, model: nil, **options, &)
48
48
  options[:builder] = BootstrapForm::FormBuilder
49
- fields(scope, model: model, **options, &block)
49
+ fields(scope, model: model, **options, &)
50
50
  end
51
51
 
52
52
  private
@@ -34,7 +34,7 @@ module BootstrapForm
34
34
 
35
35
  def label_layout_classes(custom_label_col, group_layout)
36
36
  if layout_horizontal?(group_layout)
37
- ["col-form-label", (custom_label_col || label_col)]
37
+ ["col-form-label", custom_label_col || label_col]
38
38
  elsif layout_inline?(group_layout)
39
39
  %w[form-label me-sm-2]
40
40
  else
@@ -43,10 +43,11 @@ module BootstrapForm
43
43
  end
44
44
 
45
45
  def label_text(name, options)
46
+ label = options[:text] || object&.class&.try(:human_attribute_name, name)&.html_safe # rubocop:disable Rails/OutputSafety, Style/SafeNavigationChainLength
46
47
  if label_errors && error?(name)
47
- (options[:text] || object.class.human_attribute_name(name)).to_s + " #{get_error_messages(name)}"
48
+ (" ".html_safe + get_error_messages(name)).prepend(label)
48
49
  else
49
- options[:text] || object&.class.try(:human_attribute_name, name)
50
+ label
50
51
  end
51
52
  end
52
53
  end
@@ -71,7 +71,6 @@ module BootstrapForm
71
71
  content_tag(help_tag, help_text, class: help_klass)
72
72
  end
73
73
 
74
- # rubocop:disable Metrics/AbcSize
75
74
  def get_error_messages(name)
76
75
  object.class.try(:reflections)&.each do |association_name, a|
77
76
  next unless a.is_a?(ActiveRecord::Reflection::BelongsToReflection)
@@ -82,7 +81,7 @@ module BootstrapForm
82
81
  end
83
82
  end
84
83
 
85
- object.errors[name].join(", ")
84
+ safe_join(object.errors[name], ", ")
86
85
  end
87
86
  # rubocop:enable Metrics/AbcSize
88
87
  end
@@ -1,10 +1,16 @@
1
1
  # require 'bootstrap_form/aliasing'
2
2
 
3
3
  module BootstrapForm
4
- class FormBuilder < ActionView::Helpers::FormBuilder
4
+ class FormBuilder < ActionView::Helpers::FormBuilder # rubocop:disable Metrics/ClassLength
5
5
  attr_reader :layout, :label_col, :control_col, :has_error, :inline_errors,
6
6
  :label_errors, :acts_like_form_tag
7
7
 
8
+ class << self
9
+ def redefine_rich_text_area?
10
+ ActionView::Helpers::FormBuilder.instance_methods.any? { _1 == :rich_text_area }
11
+ end
12
+ end
13
+
8
14
  include BootstrapForm::Helpers::Field
9
15
  include BootstrapForm::Helpers::Bootstrap
10
16
 
@@ -32,7 +38,7 @@ module BootstrapForm
32
38
  include BootstrapForm::Inputs::PhoneField
33
39
  include BootstrapForm::Inputs::RadioButton
34
40
  include BootstrapForm::Inputs::RangeField
35
- include BootstrapForm::Inputs::RichTextArea
41
+ include BootstrapForm::Inputs::RichTextArea if redefine_rich_text_area?
36
42
  include BootstrapForm::Inputs::SearchField
37
43
  include BootstrapForm::Inputs::Select
38
44
  include BootstrapForm::Inputs::Submit
@@ -45,6 +51,8 @@ module BootstrapForm
45
51
  include BootstrapForm::Inputs::UrlField
46
52
  include BootstrapForm::Inputs::WeekField
47
53
 
54
+ include ActionView::Helpers::OutputSafetyHelper
55
+
48
56
  delegate :content_tag, :capture, :concat, :tag, to: :@template
49
57
 
50
58
  def initialize(object_name, object, template, options)
@@ -66,14 +74,14 @@ module BootstrapForm
66
74
  return unless options[:layout] == :inline
67
75
 
68
76
  options[:html][:class] =
69
- ([*options[:html][:class]&.split(/\s+/)] + %w[row row-cols-auto g-3 align-items-center])
70
- .compact.uniq.join(" ")
77
+ safe_join(([*options[:html][:class]&.split(/\s+/)] + %w[row row-cols-auto g-3 align-items-center])
78
+ .compact.uniq, " ")
71
79
  end
72
80
 
73
- def fields_for_with_bootstrap(record_name, record_object=nil, fields_options={}, &block)
81
+ def fields_for_with_bootstrap(record_name, record_object=nil, fields_options={}, &)
74
82
  fields_options = fields_for_options(record_object, fields_options)
75
83
  record_object = nil if record_object.is_a?(Hash) && record_object.extractable_options?
76
- fields_for_without_bootstrap(record_name, record_object, fields_options, &block)
84
+ fields_for_without_bootstrap(record_name, record_object, fields_options, &)
77
85
  end
78
86
 
79
87
  bootstrap_alias :fields_for
@@ -88,9 +96,9 @@ module BootstrapForm
88
96
  field_options = fields_options
89
97
  field_options = record_object if record_object.is_a?(Hash) && record_object.extractable_options?
90
98
  %i[layout control_col inline_errors label_errors].each do |option|
91
- field_options[option] ||= options[option]
99
+ field_options[option] = field_options.key?(option) ? field_options[option] : options[option]
92
100
  end
93
- field_options[:label_col] = field_options[:label_col].present? ? (field_options[:label_col]).to_s : options[:label_col]
101
+ field_options[:label_col] = field_options[:label_col].present? ? field_options[:label_col].to_s : options[:label_col]
94
102
  field_options
95
103
  end
96
104
 
@@ -29,15 +29,15 @@ module BootstrapForm
29
29
  end
30
30
  end
31
31
 
32
- def form_group_content(label, help_text, options, &block) # rubocop:disable Metrics/AbcSize
32
+ def form_group_content(label, help_text, options, &)
33
33
  label ||= ActiveSupport::SafeBuffer.new
34
34
  if group_layout_horizontal?(options[:layout])
35
- label + tag.div(capture(&block) + help_text, class: form_group_control_class(options))
35
+ label + tag.div(capture(&) + help_text, class: form_group_control_class(options))
36
36
  else
37
37
  content = ActiveSupport::SafeBuffer.new
38
38
  # Floating labels need to be rendered after the field
39
39
  content << label unless options[:floating]
40
- content << capture(&block)
40
+ content << capture(&)
41
41
  content << label if options[:floating]
42
42
  content << help_text if help_text
43
43
  content
@@ -6,7 +6,7 @@ module BootstrapForm
6
6
 
7
7
  private
8
8
 
9
- def form_group_builder(method, options, html_options=nil, &block)
9
+ def form_group_builder(method, options, html_options=nil, &)
10
10
  no_wrapper = options[:wrapper] == false
11
11
 
12
12
  options = form_group_builder_options(options, method)
@@ -21,7 +21,7 @@ module BootstrapForm
21
21
  if no_wrapper
22
22
  yield
23
23
  else
24
- form_group(method, form_group_options, &block)
24
+ form_group(method, form_group_options, &)
25
25
  end
26
26
  end
27
27
 
@@ -91,7 +91,7 @@ module BootstrapForm
91
91
  css_options = html_options || options
92
92
  # Add control_class; allow it to be overridden by :control_class option
93
93
  control_classes = css_options.delete(:control_class) { control_class }
94
- css_options[:class] = [control_classes, css_options[:class]].compact.join(" ")
94
+ css_options[:class] = safe_join([control_classes, css_options[:class]].compact, " ")
95
95
  css_options[:class] << " is-invalid" if error?(method)
96
96
  css_options[:placeholder] = form_group_placeholder(options, method) if options[:label_as_placeholder]
97
97
  css_options
@@ -1,6 +1,8 @@
1
1
  module BootstrapForm
2
2
  module Helpers
3
3
  module Bootstrap
4
+ include ActionView::Helpers::OutputSafetyHelper
5
+
4
6
  def alert_message(title, options={})
5
7
  css = options[:class] || "alert alert-danger"
6
8
  return unless object.respond_to?(:errors) && object.errors.full_messages.any?
@@ -31,11 +33,12 @@ module BootstrapForm
31
33
  custom_class = options[:custom_class] || false
32
34
 
33
35
  tag.div class: custom_class || "invalid-feedback" do
34
- if hide_attribute_name
35
- object.errors[name].join(", ")
36
- else
37
- object.errors.full_messages_for(name).join(", ")
38
- end
36
+ errors = if hide_attribute_name
37
+ object.errors[name]
38
+ else
39
+ object.errors.full_messages_for(name)
40
+ end
41
+ safe_join(errors, ", ")
39
42
  end
40
43
  end
41
44
 
@@ -53,17 +56,17 @@ module BootstrapForm
53
56
  text_field_with_bootstrap(name, static_options)
54
57
  end
55
58
 
56
- def custom_control(*args, &block)
59
+ def custom_control(*args, &)
57
60
  options = args.extract_options!
58
61
  name = args.first
59
62
 
60
- form_group_builder(name, options, &block)
63
+ form_group_builder(name, options, &)
61
64
  end
62
65
 
63
- def prepend_and_append_input(name, options, &block)
66
+ def prepend_and_append_input(name, options, &)
64
67
  options = options.extract!(:prepend, :append, :input_group_class).compact
65
68
 
66
- input = capture(&block) || ActiveSupport::SafeBuffer.new
69
+ input = capture(&) || ActiveSupport::SafeBuffer.new
67
70
 
68
71
  input = attach_input(options, :prepend) + input + attach_input(options, :append)
69
72
  input << generate_error(name)
@@ -72,8 +75,8 @@ module BootstrapForm
72
75
  input
73
76
  end
74
77
 
75
- def input_with_error(name, &block)
76
- input = capture(&block)
78
+ def input_with_error(name, &)
79
+ input = capture(&)
77
80
  input << generate_error(name)
78
81
  end
79
82
 
@@ -93,7 +96,7 @@ module BootstrapForm
93
96
  tags = [*options[key]].map do |item|
94
97
  input_group_content(item)
95
98
  end
96
- ActiveSupport::SafeBuffer.new(tags.join)
99
+ safe_join(tags)
97
100
  end
98
101
  end
99
102
  end
@@ -6,13 +6,15 @@ module BootstrapForm
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  class_methods do
9
- def bootstrap_field(field_name, control_class: nil)
10
- define_method "#{field_name}_with_bootstrap" do |name, options={ control_class: control_class }.compact|
9
+ def bootstrap_field(field_name)
10
+ define_method :"#{field_name}_with_bootstrap" do |name, options={}|
11
11
  warn_deprecated_layout_value(options)
12
+ options = options.reverse_merge(control_class: "form-range") if field_name == :range_field
13
+ options = options.reverse_merge(control_class: "form-control form-control-color") if field_name == :color_field
12
14
  form_group_builder(name, options) do
13
15
  prepend_and_append_input(name, options) do
14
16
  options[:placeholder] ||= name if options[:floating]
15
- send("#{field_name}_without_bootstrap".to_sym, name, options.except(:floating))
17
+ send(:"#{field_name}_without_bootstrap", name, options.except(:floating))
16
18
  end
17
19
  end
18
20
  end
@@ -21,7 +23,7 @@ module BootstrapForm
21
23
  end
22
24
 
23
25
  def bootstrap_select_group(field_name)
24
- define_method("#{field_name}_with_bootstrap") do |name, options={}, html_options={}|
26
+ define_method(:"#{field_name}_with_bootstrap") do |name, options={}, html_options={}|
25
27
  html_options = html_options.reverse_merge(control_class: "form-select")
26
28
  form_group_builder(name, options, html_options) do
27
29
  form_group_content_tag(name, field_name, "#{field_name}_without_bootstrap", options, html_options)
@@ -31,9 +33,16 @@ module BootstrapForm
31
33
  bootstrap_alias field_name
32
34
  end
33
35
 
36
+ # Creates the methods *_without_bootstrap and *_with_bootstrap.
37
+ #
38
+ # If your application did not include the rails gem for one of the dsl
39
+ # methods, then a name error is raised and suppressed. This can happen
40
+ # if your application does not include the actiontext dependency due to
41
+ # `rich_text_area` not being defined.
34
42
  def bootstrap_alias(field_name)
35
- alias_method "#{field_name}_without_bootstrap".to_sym, field_name
36
- alias_method field_name, "#{field_name}_with_bootstrap".to_sym
43
+ alias_method :"#{field_name}_without_bootstrap", field_name
44
+ alias_method field_name, :"#{field_name}_with_bootstrap"
45
+ rescue NameError # rubocop:disable Lint/SuppressedException
37
46
  end
38
47
  end
39
48
 
@@ -20,6 +20,8 @@ module BootstrapForm
20
20
  end
21
21
 
22
22
  bootstrap_alias :check_box
23
+ alias_method :checkbox_with_bootstrap, :check_box_with_bootstrap if Rails::VERSION::MAJOR >= 8
24
+ bootstrap_alias :checkbox if Rails::VERSION::MAJOR >= 8
23
25
  end
24
26
 
25
27
  private
@@ -42,7 +44,7 @@ module BootstrapForm
42
44
  check_box_options.merge!(required_field_options(options, name))
43
45
  end
44
46
 
45
- def check_box_label(name, options, checked_value, &block)
47
+ def check_box_label(name, options, checked_value, &)
46
48
  label_name = if options[:multiple]
47
49
  check_box_value(name, checked_value)
48
50
  else
@@ -50,19 +52,20 @@ module BootstrapForm
50
52
  end
51
53
  label_options = { class: check_box_label_class(options) }
52
54
  label_options[:for] = options[:id] if options[:id].present?
53
- label(label_name, check_box_description(name, options, &block), label_options)
55
+ label(label_name, check_box_description(name, options, &), label_options)
54
56
  end
55
57
 
56
58
  def check_box_description(name, options, &block)
57
59
  content = block ? capture(&block) : options[:label]
58
- content || object&.class&.human_attribute_name(name) || name.to_s.humanize
60
+ # Ugh. Next Rails after 7.1 passes `false` when there's no object.
61
+ content || (object && object.class.human_attribute_name(name)) || name.to_s.humanize # rubocop:disable Style/SafeNavigation
59
62
  end
60
63
 
61
64
  def check_box_value(name, value)
62
65
  # label's `for` attribute needs to match checkbox tag's id,
63
66
  # IE sanitized value, IE
64
67
  # https://github.com/rails/rails/blob/5-0-stable/actionview/lib/action_view/helpers/tags/base.rb#L123-L125
65
- "#{name}_#{value.to_s.gsub(/\s/, '_').gsub(/[^-[[:word:]]]/, '').mb_chars.downcase}"
68
+ "#{name}_#{value.to_s.gsub(/\s/, '_').gsub(/[^-[[:word:]]]/, '').downcase}"
66
69
  end
67
70
 
68
71
  def check_box_classes(name, options)
@@ -83,7 +86,10 @@ module BootstrapForm
83
86
  def check_box_wrapper_class(options)
84
87
  classes = ["form-check"]
85
88
  classes << "form-check-inline" if layout_inline?(options[:inline])
86
- classes << "mb-3" unless options[:multiple] || %i[horizontal inline].include?(layout)
89
+ classes << "mb-3" unless options[:multiple] ||
90
+ %i[horizontal inline].include?(layout) ||
91
+ options[:wrapper_class] == false ||
92
+ options.dig(:wrapper, :class) == false
87
93
  classes << "form-switch" if options[:switch]
88
94
  classes << options.dig(:wrapper, :class).presence
89
95
  classes << options[:wrapper_class].presence
@@ -21,14 +21,8 @@ module BootstrapForm
21
21
  end
22
22
 
23
23
  bootstrap_alias :collection_check_boxes
24
-
25
- if Rails::VERSION::MAJOR < 7
26
- def field_name(method, *methods, multiple: false, index: @options[:index])
27
- object_name = @options.fetch(:as) { @object_name }
28
-
29
- @template.field_name(object_name, method, *methods, index: index, multiple: multiple)
30
- end
31
- end
24
+ alias_method :collection_checkboxes_with_bootstrap, :collection_check_boxes_with_bootstrap if Rails::VERSION::MAJOR >= 8
25
+ bootstrap_alias :collection_checkboxes if Rails::VERSION::MAJOR >= 8
32
26
  end
33
27
  end
34
28
  end
@@ -10,7 +10,7 @@ module BootstrapForm
10
10
  def file_field_with_bootstrap(name, options={})
11
11
  options = options.reverse_merge(control_class: "form-control")
12
12
  form_group_builder(name, options) do
13
- input_with_error(name) do
13
+ prepend_and_append_input(name, options) do
14
14
  file_field_without_bootstrap(name, options)
15
15
  end
16
16
  end
@@ -7,7 +7,7 @@ module BootstrapForm
7
7
  include Base
8
8
 
9
9
  included do
10
- bootstrap_field :range_field, control_class: "form-range"
10
+ bootstrap_field :range_field
11
11
  end
12
12
  end
13
13
  end
@@ -10,13 +10,15 @@ module BootstrapForm
10
10
  def rich_text_area_with_bootstrap(name, options={})
11
11
  form_group_builder(name, options) do
12
12
  prepend_and_append_input(name, options) do
13
- options[:class] = ["trix-content", options[:class]].compact.join(" ")
13
+ options[:class] = safe_join(["trix-content", options[:class]].compact, " ")
14
14
  rich_text_area_without_bootstrap(name, options)
15
15
  end
16
16
  end
17
17
  end
18
18
 
19
19
  bootstrap_alias :rich_text_area
20
+ alias_method :rich_textarea, :rich_text_area if Rails::VERSION::MAJOR >= 8
21
+ bootstrap_alias :rich_textarea if Rails::VERSION::MAJOR >= 8
20
22
  end
21
23
  end
22
24
  end
@@ -1,7 +1,7 @@
1
1
  module BootstrapForm
2
2
  module Inputs
3
3
  module Submit
4
- def button(value=nil, options={}, &block)
4
+ def button(value=nil, options={}, &)
5
5
  value = setup_css_class "btn btn-secondary", value, options
6
6
  super
7
7
  end
@@ -8,6 +8,8 @@ module BootstrapForm
8
8
 
9
9
  included do
10
10
  bootstrap_field :text_area
11
+ alias_method :textarea_with_bootstrap, :text_area_with_bootstrap if Rails::VERSION::MAJOR >= 8
12
+ bootstrap_field :textarea if Rails::VERSION::MAJOR >= 8
11
13
  end
12
14
  end
13
15
  end
@@ -1,4 +1,4 @@
1
1
  module BootstrapForm
2
- VERSION = "5.3.2".freeze
3
- REQUIRED_RAILS_VERSION = ">= 6.1".freeze
2
+ VERSION = "5.5.0".freeze
3
+ REQUIRED_RAILS_VERSION = ">= 7.2".freeze
4
4
  end
@@ -1,9 +1,3 @@
1
- # NOTE: The rich_text_area and rich_text_area_tag helpers are defined in a file with a different
2
- # name and not in the usual autoload-reachable way.
3
- # The following line is definitely need to make `bootstrap_form` work.
4
- if Rails::VERSION::STRING > "6"
5
- require "#{Gem::Specification.find_by_name('actiontext').gem_dir}/app/helpers/action_text/tag_helper"
6
- end
7
1
  require "action_view"
8
2
  require "action_pack"
9
3
  require "bootstrap_form/action_view_extensions/form_helper"