rails_bootstrap_form 0.9.7 → 0.9.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ffc0cdcd818f57b7e0b683ec59b2ac3a59b80edab6e40f9eebe1da8d32cd376
4
- data.tar.gz: 676be2383b1d1421b70a50ad5dc044eed15dfe4707b26ca345077644de9abebc
3
+ metadata.gz: 73b8b86f78e40f77d36ba3857ef15c9efe939480d327011ba083132d48668654
4
+ data.tar.gz: 897ed641bdc6147d29698901a0b9f37ce71a46d0581734a844cf03666fbf5c20
5
5
  SHA512:
6
- metadata.gz: cdf31544bc3fd0032dff7b12bb95b1af33466d8e5a199ea0ecd263e1a8cdfdc2d00b02cc95425a1e712c6f2edd8ca626cf5e9ca6523fdf7eecf66a5a4776b17e
7
- data.tar.gz: 60e72524a66706827e25fd018ffbe4dc75e823d346a86627c525e0e9f095af6a490846dc04526127708f4c30811f59c30c94b32936543055dcc6bf2fd6a3af4f
6
+ metadata.gz: 0b5ee6a90da2f11246c01c6f41f01d0fe067cd07ba26b56773e50b6c67c3b87e67d8714694c0c11240d31cb8d58255c58610dbf6304cea21fd547abdc718f8db
7
+ data.tar.gz: 1554395fcabb6df7f38722c5a26eb680b8436c7bd54f9567477db6b302208872d53417abca1d219a89f48c7fcff8ff8b22e9c26aafa194c79bd683eb83a2ed85
data/.codeclimate.yml ADDED
@@ -0,0 +1,47 @@
1
+ version: "2"
2
+ checks:
3
+ argument-count:
4
+ enabled: true
5
+ config:
6
+ threshold: 4
7
+ complex-logic:
8
+ enabled: true
9
+ config:
10
+ threshold: 4
11
+ file-lines:
12
+ enabled: true
13
+ config:
14
+ threshold: 250
15
+ method-complexity:
16
+ enabled: true
17
+ config:
18
+ threshold: 5
19
+ method-count:
20
+ enabled: true
21
+ config:
22
+ threshold: 20
23
+ method-lines:
24
+ enabled: true
25
+ config:
26
+ threshold: 25
27
+ nested-control-flow:
28
+ enabled: true
29
+ config:
30
+ threshold: 4
31
+ return-statements:
32
+ enabled: true
33
+ config:
34
+ threshold: 4
35
+ exclude_patterns:
36
+ - "config/"
37
+ - "db/"
38
+ - "dist/"
39
+ - "features/"
40
+ - "demo/"
41
+ - "**/node_modules/"
42
+ - "script/"
43
+ - "**/spec/"
44
+ - "**/test/"
45
+ - "**/tests/"
46
+ - "**/vendor/"
47
+ - "**/*.d.ts"
data/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ You can find recent releases with docs in GitHub:
4
4
 
5
5
  https://github.com/shivam091/rails_bootstrap_form/releases
6
6
 
7
+ ## [0.9.8](https://github.com/shivam091/rails_bootstrap_form/compare/v0.9.7...v0.9.8) - 2023-07-01
8
+
9
+ ### What's fixed
10
+
11
+ - Fixed bug causing button helpers not to work with block and options ([#50](https://github.com/shivam091/rails_bootstrap_form/issues/50))
12
+
7
13
  ## [0.9.7](https://github.com/shivam091/rails_bootstrap_form/compare/v0.9.6...v0.9.7) - 2023-06-26
8
14
 
9
15
  ### What's new
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_bootstrap_form (0.9.7)
4
+ rails_bootstrap_form (0.9.8)
5
5
  actionpack (~> 7.0)
6
6
  activemodel (~> 7.0)
7
7
 
data/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  [![Ruby](https://github.com/shivam091/rails_bootstrap_form/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/shivam091/rails_bootstrap_form/actions/workflows/main.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/rails_bootstrap_form.svg)](https://badge.fury.io/rb/rails_bootstrap_form)
5
+ [![Gem Downloads](https://img.shields.io/gem/dt/rails_bootstrap_form.svg)](http://rubygems.org/gems/rails_bootstrap_form)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/8038de955c10394ae35d/test_coverage)](https://codeclimate.com/github/shivam091/rails_bootstrap_form/test_coverage)
7
+ [![Maintainability](https://api.codeclimate.com/v1/badges/8038de955c10394ae35d/maintainability)](https://codeclimate.com/github/shivam091/rails_bootstrap_form/maintainability)
5
8
 
6
9
  **rails_bootstrap_form** is a Rails form builder that makes it super easy to integrate [Bootstrap 5](https://getbootstrap.com/) forms into your Rails application.
7
10
  `rails_bootstrap_form`'s form helpers generate the form field and its label along with all the Bootstrap mark-up required for proper Bootstrap display.
@@ -28,7 +31,7 @@ for setting up `application.scss` and `application.js`.
28
31
  Add the `rails_bootstrap_form` gem to your `Gemfile`:
29
32
 
30
33
  ```ruby
31
- gem "rails_bootstrap_form", "~> 0.9.6"
34
+ gem "rails_bootstrap_form", "~> 0.9.8"
32
35
  ```
33
36
 
34
37
  Then:
@@ -13,7 +13,7 @@ module RailsBootstrapForm
13
13
  include RailsBootstrapForm::InputGroupBuilder
14
14
  include RailsBootstrapForm::Inputs
15
15
 
16
- delegate :capture, :concat, :tag, to: :@template
16
+ delegate :capture, :concat, :tag, :button_tag, to: :@template
17
17
 
18
18
  attr_accessor :bootstrap_form_options
19
19
 
@@ -4,6 +4,9 @@
4
4
 
5
5
  module RailsBootstrapForm
6
6
  module FieldWrapperBuilder
7
+
8
+ private
9
+
7
10
  def field_wrapper_builder(attribute, bootstrap, options, html_options = nil, &block)
8
11
  field_options = field_css_options(attribute, bootstrap, options, html_options.try(:symbolize_keys!))
9
12
 
@@ -15,37 +18,17 @@ module RailsBootstrapForm
15
18
  help_text = help_text(attribute, bootstrap)
16
19
  wrapper_content = ActiveSupport::SafeBuffer.new
17
20
 
18
- if bootstrap.layout_horizontal?
19
- wrapper_content << label
20
- wrapper_content << tag.div(class: bootstrap.field_col_wrapper_class) do
21
- input_group_wrapper(attribute, bootstrap) do
22
- capture(&block)
23
- end + help_text
24
- end
21
+ wrapper_content = if bootstrap.layout_horizontal?
22
+ build_horizontal_layout_content(attribute, bootstrap, label, help_text, &block)
25
23
  else
26
24
  if bootstrap.floating?
27
- wrapper_content << input_group_wrapper(attribute, bootstrap) do
28
- tag.div(class: floating_label_classes(attribute)) do
29
- capture(&block) + label
30
- end
31
- end
32
- wrapper_content << help_text
25
+ build_floating_layout_content(attribute, bootstrap, label, help_text, &block)
33
26
  else
34
- wrapper_content << label
35
- wrapper_content << input_group_wrapper(attribute, bootstrap) do
36
- capture(&block)
37
- end
38
- wrapper_content << help_text
27
+ build_default_layout_content(attribute, bootstrap, label, help_text, &block)
39
28
  end
40
29
  end
41
30
 
42
- if bootstrap.wrapper
43
- tag.div(**field_wrapper_options(bootstrap)) do
44
- wrapper_content
45
- end
46
- else
47
- wrapper_content
48
- end
31
+ build_wrapper_element(bootstrap, wrapper_content)
49
32
  end
50
33
 
51
34
  def field_wrapper_options(bootstrap)
@@ -72,18 +55,11 @@ module RailsBootstrapForm
72
55
  def field_css_options(attribute, bootstrap, options, html_options)
73
56
  css_options = (html_options || options)
74
57
 
75
- field_classes = Array(bootstrap.field_class) << [bootstrap.additional_field_class || css_options[:class]]
76
- field_classes << "is-invalid" if is_invalid?(attribute)
77
- if is_size_valid?(bootstrap)
78
- field_classes << "#{bootstrap.field_class}-#{bootstrap.size}"
79
- end
58
+ field_classes = build_field_classes(attribute, bootstrap, css_options)
80
59
 
81
60
  css_options[:class] = field_classes.flatten.compact
82
61
  css_options.merge!(required_field_options(attribute, options))
83
-
84
- if placeholder_required?(bootstrap)
85
- css_options[:placeholder] ||= label_text(attribute, bootstrap)
86
- end
62
+ add_placeholder_if_required!(css_options, attribute, bootstrap)
87
63
 
88
64
  css_options
89
65
  end
@@ -96,11 +72,63 @@ module RailsBootstrapForm
96
72
  classes
97
73
  end
98
74
 
75
+ def build_field_classes(attribute, bootstrap, css_options)
76
+ field_classes = Array(bootstrap.field_class) <<
77
+ field_classes << [bootstrap.additional_field_class || css_options[:class]]
78
+ field_classes << "is-invalid" if is_invalid?(attribute)
79
+ field_classes << "#{bootstrap.field_class}-#{bootstrap.size}" if is_size_valid?(bootstrap)
80
+ field_classes
81
+ end
82
+
99
83
  def placeholder_required?(bootstrap)
100
84
  (bootstrap.floating? && !bootstrap.layout_horizontal?) || bootstrap.layout_inline?
101
85
  end
102
86
 
103
- private :field_wrapper, :field_wrapper_classes, :field_wrapper_default_class,
104
- :field_css_options, :floating_label_classes
87
+ def add_placeholder_if_required!(css_options, attribute, bootstrap)
88
+ css_options[:placeholder] ||= label_text(attribute, bootstrap) if placeholder_required?(bootstrap)
89
+ css_options
90
+ end
91
+
92
+ def build_horizontal_layout_content(attribute, bootstrap, label, help_text, &block)
93
+ wrapper_content = ActiveSupport::SafeBuffer.new
94
+ wrapper_content << label
95
+ wrapper_content << tag.div(class: bootstrap.field_col_wrapper_class) do
96
+ input_group_wrapper(attribute, bootstrap) do
97
+ capture(&block)
98
+ end + help_text
99
+ end
100
+ wrapper_content
101
+ end
102
+
103
+ def build_floating_layout_content(attribute, bootstrap, label, help_text, &block)
104
+ wrapper_content = ActiveSupport::SafeBuffer.new
105
+ wrapper_content << input_group_wrapper(attribute, bootstrap) do
106
+ tag.div(class: floating_label_classes(attribute)) do
107
+ capture(&block) + label
108
+ end
109
+ end
110
+ wrapper_content << help_text
111
+ wrapper_content
112
+ end
113
+
114
+ def build_default_layout_content(attribute, bootstrap, label, help_text, &block)
115
+ wrapper_content = ActiveSupport::SafeBuffer.new
116
+ wrapper_content << label
117
+ wrapper_content << input_group_wrapper(attribute, bootstrap) do
118
+ capture(&block)
119
+ end
120
+ wrapper_content << help_text
121
+ wrapper_content
122
+ end
123
+
124
+ def build_wrapper_element(bootstrap, wrapper_content)
125
+ if bootstrap.wrapper
126
+ tag.div(**field_wrapper_options(bootstrap)) do
127
+ wrapper_content
128
+ end
129
+ else
130
+ wrapper_content
131
+ end
132
+ end
105
133
  end
106
134
  end
@@ -7,37 +7,67 @@ module RailsBootstrapForm
7
7
  module Buttons
8
8
  extend ActiveSupport::Concern
9
9
 
10
- def self.included(base_class)
11
- def render_button(value = nil, options = {}, &block)
12
- value, options = nil, value if value.is_a?(Hash)
10
+ included do
11
+ def button(value, options, &block)
13
12
  bootstrap = bootstrap_form_options.scoped(options.delete(:bootstrap))
13
+ value, options = extract_button_value_and_options(value, options)
14
14
 
15
- button_html = if (bootstrap.render_as_button? || block)
16
- button(value, options, &block)
17
- else
18
- submit(value, options)
19
- end
20
-
21
- if bootstrap.layout_inline?
22
- tag.div(class: "col-12") { button_html }
23
- else
24
- button_html
25
- end
15
+ add_button_css_classes!(options, bootstrap)
16
+
17
+ button_html = render_button_html(value, options, bootstrap, &block)
18
+ button_html = wrap_button_html(button_html, bootstrap)
19
+
20
+ button_html
26
21
  end
27
22
 
28
23
  def secondary(value = nil, options = {}, &block)
29
- add_css_class!(options, "btn btn-secondary")
30
- render_button(value, options, &block)
24
+ button(value, options.merge!(variant: "secondary"), &block)
31
25
  end
32
26
 
33
27
  def primary(value = nil, options = {}, &block)
34
- add_css_class!(options, "btn btn-primary")
35
- render_button(value, options, &block)
28
+ button(value, options.merge!(variant: "primary"), &block)
36
29
  end
37
30
 
38
31
  def danger(value = nil, options = {}, &block)
39
- add_css_class!(options, "btn btn-danger")
40
- render_button(value, options, &block)
32
+ button(value, options.merge!(variant: "danger"), &block)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def button_variant_class(options)
39
+ case options.delete(:variant)
40
+ when "secondary" then "btn-secondary"
41
+ when "primary" then "btn-primary"
42
+ when "danger" then "btn-danger"
43
+ else ""
44
+ end
45
+ end
46
+
47
+ def extract_button_value_and_options(value, options)
48
+ return [nil, value.merge(options)] if value.is_a?(Hash)
49
+
50
+ [value, options]
51
+ end
52
+
53
+ def add_button_css_classes!(options, bootstrap)
54
+ add_css_class!(options, "btn")
55
+ add_css_class!(options, button_variant_class(options))
56
+ end
57
+
58
+ def render_button_html(value, options, bootstrap, &block)
59
+ if bootstrap.render_as_button? || block
60
+ button_tag(value, options, &block)
61
+ else
62
+ submit(value, options)
63
+ end
64
+ end
65
+
66
+ def wrap_button_html(button_html, bootstrap)
67
+ if bootstrap.layout_inline?
68
+ tag.div(class: "col-12") { button_html }
69
+ else
70
+ button_html
41
71
  end
42
72
  end
43
73
  end
@@ -7,76 +7,92 @@ module RailsBootstrapForm
7
7
  module Choice
8
8
  extend ActiveSupport::Concern
9
9
 
10
- def self.included(base_class)
11
- [:check_box, :radio_button].each do |tag_name|
12
- define_method("#{tag_name}_label") do |attribute, value, options, bootstrap|
13
- unless bootstrap.skip_label?
14
- label_options = {
15
- class: choice_label_classes(attribute, bootstrap, options)
16
- }
17
- label_options[:value] = value if tag_name.eql?(:radio_button)
18
- label_options[:for] = options[:id] if options[:id].present?
10
+ private
19
11
 
20
- label_text = label_text(attribute, bootstrap)
12
+ [:check_box, :radio_button].each do |tag_name|
13
+ define_method("#{tag_name}_label") do |attribute, value, options, bootstrap|
14
+ unless bootstrap.skip_label?
15
+ label_options = {
16
+ class: choice_label_classes(attribute, bootstrap, options)
17
+ }
18
+ label_options[:value] = value if tag_name.eql?(:radio_button)
19
+ label_options[:for] = options[:id] if options[:id].present?
21
20
 
22
- label(attribute, label_text, label_options)
23
- end
21
+ label_text = label_text(attribute, bootstrap)
22
+
23
+ label(attribute, label_text, label_options)
24
24
  end
25
25
  end
26
+ end
26
27
 
27
- [:check_box, :radio_button].each do |tag_name|
28
- define_method("bootstrap_#{tag_name}") do |attribute, value, options, bootstrap|
29
- options[:class] = choice_classes(attribute, bootstrap, options)
30
-
31
- if tag_name.eql?(:check_box)
32
- choice_field = check_box_without_bootstrap(attribute, options, value, nil)
33
- choice_label = check_box_label(attribute, value, options, bootstrap)
34
- else
35
- choice_field = radio_button_without_bootstrap(attribute, value, options)
36
- choice_label = radio_button_label(attribute, value, options, bootstrap)
37
- end
28
+ [:check_box, :radio_button].each do |tag_name|
29
+ define_method("bootstrap_#{tag_name}") do |attribute, value, options, bootstrap|
30
+ options[:class] = choice_classes(attribute, bootstrap, options)
38
31
 
39
- choice_field + choice_label
32
+ if tag_name.eql?(:check_box)
33
+ choice_field = check_box_without_bootstrap(attribute, options, value, nil)
34
+ choice_label = check_box_label(attribute, value, options, bootstrap)
35
+ else
36
+ choice_field = radio_button_without_bootstrap(attribute, value, options)
37
+ choice_label = radio_button_label(attribute, value, options, bootstrap)
40
38
  end
41
- end
42
39
 
43
- def choice_classes(attribute, bootstrap, options)
44
- classes = Array("form-check-input") << [bootstrap.additional_field_class || options[:class]]
45
- classes << "is-invalid" if is_invalid?(attribute)
46
- classes.flatten.compact
40
+ choice_field + choice_label
47
41
  end
42
+ end
48
43
 
49
- def choice_label_classes(attribute, bootstrap, options)
50
- classes = Array("form-check-label") << bootstrap.additional_label_class
51
- classes << "required" if is_field_required?(attribute, options)
52
- classes << "is-invalid" if is_invalid?(attribute)
53
- classes << bootstrap.hide_class if bootstrap.hide_label?
54
- classes.flatten.compact
44
+ [:check_box, :radio_button].each do |tag_name|
45
+ define_method("build_#{tag_name}_html") do |attribute, value, bootstrap, options|
46
+ tag.div(class: choice_wrapper_classes(bootstrap)) do
47
+ concat(send("bootstrap_#{tag_name}", attribute, value, options, bootstrap))
48
+ concat(help_text(attribute, bootstrap))
49
+ concat(generate_error(attribute)) if is_invalid?(attribute)
50
+ end
55
51
  end
52
+ end
56
53
 
57
- def choice_container_classes(bootstrap)
58
- classes = Array(bootstrap.field_col_wrapper_class)
59
- classes << field_offset_class(bootstrap.label_col_wrapper_class)
60
- classes.flatten.compact
54
+ [:check_box, :radio_button].each do |tag_name|
55
+ define_method("build_wrapped_#{tag_name}_html") do |bootstrap, tag_html|
56
+ tag.div(**field_wrapper_options(bootstrap)) do
57
+ if bootstrap.layout_horizontal?
58
+ tag.div(class: choice_container_classes(bootstrap)) { tag_html }
59
+ else
60
+ tag_html
61
+ end
62
+ end
61
63
  end
64
+ end
62
65
 
63
- def choice_wrapper_classes(bootstrap)
64
- classes = Array("form-check")
65
- classes << "form-check-inline" if bootstrap.inline?
66
- classes << "form-switch" if bootstrap.switch?
67
- classes.flatten.compact
68
- end
66
+ def choice_classes(attribute, bootstrap, options)
67
+ classes = Array("form-check-input") << [bootstrap.additional_field_class || options[:class]]
68
+ classes << "is-invalid" if is_invalid?(attribute)
69
+ classes.flatten.compact
70
+ end
69
71
 
70
- def collection_input_checked?(checked, obj, input_value)
71
- checked == input_value || Array(checked).try(:include?, input_value) ||
72
- checked == obj || Array(checked).try(:include?, obj)
73
- end
72
+ def choice_label_classes(attribute, bootstrap, options)
73
+ classes = Array("form-check-label") << bootstrap.additional_label_class
74
+ classes << "required" if is_field_required?(attribute, options)
75
+ classes << "is-invalid" if is_invalid?(attribute)
76
+ classes << bootstrap.hide_class if bootstrap.hide_label?
77
+ classes.flatten.compact
78
+ end
79
+
80
+ def choice_container_classes(bootstrap)
81
+ classes = Array(bootstrap.field_col_wrapper_class)
82
+ classes << field_offset_class(bootstrap.label_col_wrapper_class)
83
+ classes.flatten.compact
84
+ end
85
+
86
+ def choice_wrapper_classes(bootstrap)
87
+ classes = Array("form-check")
88
+ classes << "form-check-inline" if bootstrap.inline?
89
+ classes << "form-switch" if bootstrap.switch?
90
+ classes.flatten.compact
91
+ end
74
92
 
75
- private :choice_classes, :choice_label_classes,
76
- :choice_container_classes, :choice_wrapper_classes,
77
- :check_box_label, :radio_button_label,
78
- :bootstrap_check_box, :bootstrap_radio_button,
79
- :collection_input_checked?
93
+ def collection_input_checked?(checked, obj, input_value)
94
+ checked == input_value || Array(checked).try(:include?, input_value) ||
95
+ checked == obj || Array(checked).try(:include?, obj)
80
96
  end
81
97
  end
82
98
  end
@@ -7,59 +7,69 @@ module RailsBootstrapForm
7
7
  module Errors
8
8
  extend ActiveSupport::Concern
9
9
 
10
- def self.included(base_class)
11
- def is_invalid?(attribute)
12
- (attribute && object.respond_to?(:errors) && object.errors[attribute].any?) ||
13
- has_association_error?(attribute)
14
- end
10
+ private
15
11
 
16
- # def input_with_error(attribute, &block)
17
- # input = capture(&block)
18
- # input << generate_error(attribute)
19
- # input
20
- # end
12
+ def is_invalid?(attribute)
13
+ (attribute && object.respond_to?(:errors) && has_attribute_error?(attribute)) ||
14
+ has_association_error?(attribute)
15
+ end
21
16
 
22
- def generate_error(attribute)
23
- if is_invalid?(attribute)
24
- error_text = error_messages(attribute)
25
- error_klass = "invalid-feedback"
17
+ def generate_error(attribute)
18
+ if is_invalid?(attribute)
19
+ error_text = error_messages(attribute)
20
+ error_klass = "invalid-feedback"
26
21
 
27
- tag.div(error_text, class: error_klass)
28
- end
22
+ tag.div(error_text, class: error_klass)
29
23
  end
24
+ end
25
+
26
+ def error_messages(attribute)
27
+ messages = Array(attribute_error_messages(attribute))
28
+ messages << associated_error_messages(attribute)
30
29
 
31
- def has_association_error?(attribute)
32
- object.class.try(:reflections)&.any? do |association_name, association|
33
- next unless is_belongs_to_association?(association)
34
- next unless is_association_same?(attribute, association)
30
+ messages.flatten.to_sentence
31
+ end
32
+
33
+ def has_attribute_error?(attribute)
34
+ attribute_error_messages(attribute).any?
35
+ end
35
36
 
36
- object.errors[association_name].any?
37
- end
37
+ def has_association_error?(attribute)
38
+ object.class.try(:reflections)&.any? do |association_name, association|
39
+ has_errors_on_association?(attribute, association_name)
38
40
  end
41
+ end
39
42
 
40
- def error_messages(attribute)
41
- messages = object.errors[attribute]
43
+ def has_errors_on_association?(attribute, association_name)
44
+ return false unless is_belongs_to_association?(object.class.reflections[association_name])
45
+ return false unless is_association_same?(attribute, object.class.reflections[association_name])
42
46
 
43
- object.class.try(:reflections)&.each do |association_name, association|
44
- next unless is_belongs_to_association?(association)
45
- next unless is_association_same?(attribute, association)
47
+ object.errors[association_name].any?
48
+ end
46
49
 
47
- messages << object.errors[association_name]
48
- end
50
+ def attribute_error_messages(attribute)
51
+ object.errors[attribute]
52
+ end
49
53
 
50
- messages.flatten.to_sentence
51
- end
54
+ def associated_error_messages(attribute)
55
+ error_messages = []
52
56
 
53
- def is_belongs_to_association?(association)
54
- association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
55
- end
57
+ object.class.try(:reflections)&.each do |association_name, association|
58
+ next unless is_belongs_to_association?(association)
59
+ next unless is_association_same?(attribute, association)
56
60
 
57
- def is_association_same?(attribute, association)
58
- (association.foreign_key == attribute.to_s)
61
+ error_messages << object.errors[association_name]
59
62
  end
60
63
 
61
- private :is_invalid?, :generate_error, :has_association_error?,
62
- :error_messages, :is_belongs_to_association?, :is_association_same?
64
+ error_messages
65
+ end
66
+
67
+ def is_belongs_to_association?(association)
68
+ association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
69
+ end
70
+
71
+ def is_association_same?(attribute, association)
72
+ (association.foreign_key == attribute.to_s)
63
73
  end
64
74
  end
65
75
  end
@@ -7,46 +7,43 @@ module RailsBootstrapForm
7
7
  module HelpText
8
8
  extend ActiveSupport::Concern
9
9
 
10
- def self.included(base_class)
11
- def help_text(attribute, bootstrap)
12
- return if bootstrap.help_text == false
10
+ private
13
11
 
14
- help_text = (bootstrap.help_text || scoped_help_text(attribute))
12
+ def help_text(attribute, bootstrap)
13
+ return if bootstrap.help_text == false
15
14
 
16
- tag.div(help_text, class: "form-text text-muted") if help_text.present?
17
- end
15
+ help_text = (bootstrap.help_text || scoped_help_text(attribute))
18
16
 
19
- def object_class
20
- if !object.class.is_a?(ActiveModel::Naming) &&
21
- object.respond_to?(:klass) && object.klass.is_a?(ActiveModel::Naming)
22
- object.klass
23
- else
24
- object.class
25
- end
26
- end
17
+ tag.div(help_text, class: "form-text text-muted") if help_text.present?
18
+ end
27
19
 
28
- def partial_scope
29
- if object_class.respond_to?(:model_name)
30
- object_class.model_name.name
31
- else
32
- object_class.name
33
- end
20
+ def object_class
21
+ if !object.class.is_a?(ActiveModel::Naming) &&
22
+ object.respond_to?(:klass) && object.klass.is_a?(ActiveModel::Naming)
23
+ object.klass
24
+ else
25
+ object.class
34
26
  end
27
+ end
35
28
 
36
- def scoped_help_text(attribute)
37
- translation_scope = "activerecord.help_texts.#{partial_scope.underscore}"
29
+ def partial_scope
30
+ if object_class.respond_to?(:model_name)
31
+ object_class.model_name.name
32
+ else
33
+ object_class.name
34
+ end
35
+ end
38
36
 
39
- help_text = translated_help_text(attribute, translation_scope).presence
37
+ def scoped_help_text(attribute)
38
+ translation_scope = "activerecord.help_texts.#{partial_scope.underscore}"
40
39
 
41
- help_text
42
- end
40
+ help_text = translated_help_text(attribute, translation_scope).presence
43
41
 
44
- def translated_help_text(attribute, scope)
45
- ActiveSupport::SafeBuffer.new(I18n.t(attribute, scope: scope, default: ""))
46
- end
42
+ help_text
43
+ end
47
44
 
48
- private :help_text, :partial_scope, :object_class, :scoped_help_text
49
- :translated_help_text
45
+ def translated_help_text(attribute, scope)
46
+ ActiveSupport::SafeBuffer.new(I18n.t(attribute, scope: scope, default: ""))
50
47
  end
51
48
  end
52
49
  end
@@ -7,47 +7,44 @@ module RailsBootstrapForm
7
7
  module Labels
8
8
  extend ActiveSupport::Concern
9
9
 
10
- def self.included(base_class)
11
- def draw_label(attribute, options, bootstrap)
12
- unless bootstrap.skip_label? && !bootstrap.floating?
13
- label_options = {
14
- class: label_classes(attribute, options, bootstrap)
15
- }
16
- label_options[:for] = options[:id] if options[:id].present?
17
- label_text = label_text(attribute, bootstrap)
18
-
19
- label(attribute, label_text, label_options)
20
- end
21
- end
10
+ private
22
11
 
23
- def label_classes(attribute, options, bootstrap)
24
- classes = []
25
- classes << label_layout_classes(bootstrap)
26
- classes << bootstrap.additional_label_class
27
- classes << bootstrap.hide_class if hide_class_required?(bootstrap)
28
- classes << "required" if is_field_required?(attribute, options)
29
- classes << "is-invalid" if is_invalid?(attribute)
30
- classes.flatten.compact
31
- end
12
+ def draw_label(attribute, options, bootstrap)
13
+ unless bootstrap.skip_label? && !bootstrap.floating?
14
+ label_options = {
15
+ class: label_classes(attribute, options, bootstrap)
16
+ }
17
+ label_options[:for] = options[:id] if options[:id].present?
18
+ label_text = label_text(attribute, bootstrap)
32
19
 
33
- def label_layout_classes(bootstrap)
34
- if bootstrap.layout_horizontal?
35
- [bootstrap.label_col_class, bootstrap.label_col_wrapper_class]
36
- else
37
- bootstrap.label_class
38
- end
20
+ label(attribute, label_text, label_options)
39
21
  end
22
+ end
40
23
 
41
- def label_text(attribute, bootstrap)
42
- bootstrap.label_text || object&.class.try(:human_attribute_name, attribute)
43
- end
24
+ def label_classes(attribute, options, bootstrap)
25
+ classes = []
26
+ classes << label_layout_classes(bootstrap)
27
+ classes << bootstrap.additional_label_class
28
+ classes << bootstrap.hide_class if hide_class_required?(bootstrap)
29
+ classes << "required" if is_field_required?(attribute, options)
30
+ classes << "is-invalid" if is_invalid?(attribute)
31
+ classes.flatten.compact
32
+ end
44
33
 
45
- def hide_class_required?(bootstrap)
46
- bootstrap.hide_label? || (bootstrap.layout_inline? && !bootstrap.floating?)
34
+ def label_layout_classes(bootstrap)
35
+ if bootstrap.layout_horizontal?
36
+ [bootstrap.label_col_class, bootstrap.label_col_wrapper_class]
37
+ else
38
+ bootstrap.label_class
47
39
  end
40
+ end
41
+
42
+ def label_text(attribute, bootstrap)
43
+ bootstrap.label_text || object&.class.try(:human_attribute_name, attribute)
44
+ end
48
45
 
49
- private :draw_label, :label_classes, :label_text, :label_layout_classes,
50
- :hide_class_required?
46
+ def hide_class_required?(bootstrap)
47
+ bootstrap.hide_label? || (bootstrap.layout_inline? && !bootstrap.floating?)
51
48
  end
52
49
  end
53
50
  end
@@ -7,57 +7,61 @@ module RailsBootstrapForm
7
7
  module RequiredField
8
8
  extend ActiveSupport::Concern
9
9
 
10
- def self.included(base_class)
11
- def is_field_required?(attribute, options)
12
- return false unless attribute
10
+ private
13
11
 
14
- if options.key?(:required)
15
- options[:required]
16
- else
17
- is_attribute_required?(attribute)
18
- end
12
+ def is_field_required?(attribute, options)
13
+ return false unless attribute
14
+
15
+ if options.key?(:required)
16
+ options[:required]
17
+ else
18
+ is_attribute_required?(attribute)
19
19
  end
20
+ end
20
21
 
21
- def required_field_options(attribute, options)
22
- required = is_field_required?(attribute, options)
22
+ def required_field_options(attribute, options)
23
+ required = is_field_required?(attribute, options)
23
24
 
24
- {}.tap do |option|
25
- option[:aria] = {required: true} if required
26
- option[:required] = required
27
- end
25
+ {}.tap do |option|
26
+ option[:aria] = {required: true} if required
27
+ option[:required] = required
28
28
  end
29
+ end
29
30
 
30
- def is_attribute_required?(attribute)
31
- return false unless attribute
31
+ def is_attribute_required?(attribute)
32
+ return false unless attribute
32
33
 
33
- target = object.instance_of?(Class) ? object : object.class
34
- return false unless target.respond_to?(:validators_on)
34
+ target = target_object(object)
35
+ return false unless target.respond_to?(:validators_on)
35
36
 
36
- has_presence_validator?(target_validators(target, attribute)) ||
37
- is_required_association?(target, attribute)
38
- end
37
+ has_presence_validator?(target_validators(target, attribute)) || is_required_association?(target, attribute)
38
+ end
39
39
 
40
- def target_validators(target, attribute)
41
- target.validators_on(attribute).map(&:class)
42
- end
40
+ def target_object(object)
41
+ object.instance_of?(Class) ? object : object.class
42
+ end
43
43
 
44
- def has_presence_validator?(target_validators)
45
- target_validators.include?(ActiveModel::Validations::PresenceValidator) ||
46
- (defined?(ActiveRecord::Validations::PresenceValidator) &&
47
- target_validators.include?(ActiveRecord::Validations::PresenceValidator))
48
- end
44
+ def target_validators(target, attribute)
45
+ target.validators_on(attribute).map(&:class)
46
+ end
49
47
 
50
- def is_required_association?(target, attribute)
51
- target.try(:reflections)&.find do |name, a|
52
- next unless a.is_a?(ActiveRecord::Reflection::BelongsToReflection)
53
- next unless a.foreign_key == attribute.to_s
48
+ def has_presence_validator?(target_validators)
49
+ target_validators.include?(ActiveModel::Validations::PresenceValidator) ||
50
+ (defined?(ActiveRecord::Validations::PresenceValidator) &&
51
+ target_validators.include?(ActiveRecord::Validations::PresenceValidator))
52
+ end
54
53
 
55
- has_presence_validator?(target_validators(target, name))
56
- end
54
+ def is_required_association?(target, attribute)
55
+ target.try(:reflections)&.find do |name, reflection|
56
+ required_association?(reflection, attribute)
57
57
  end
58
+ end
59
+
60
+ def required_association?(reflection, attribute)
61
+ return false unless reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection)
62
+ return false unless reflection.foreign_key == attribute.to_s
58
63
 
59
- private :is_field_required?, :required_field_options, :target_validators,
60
- :has_presence_validator?, :is_required_association?
64
+ has_presence_validator?(target_validators(reflection.active_record, reflection.name))
61
65
  end
62
66
  end
63
67
  end
@@ -6,58 +6,55 @@ module RailsBootstrapForm
6
6
  module InputGroupBuilder
7
7
  extend ActiveSupport::Concern
8
8
 
9
- def self.included(base_class)
10
- def input_group_wrapper(attribute, bootstrap, &block)
11
- input = capture(&block) || ActiveSupport::SafeBuffer.new
9
+ private
12
10
 
13
- if input_group_required?(bootstrap)
14
- prepend = attach_input(bootstrap, :prepend)
15
- append = attach_input(bootstrap, :append)
11
+ def input_group_wrapper(attribute, bootstrap, &block)
12
+ input = capture(&block) || ActiveSupport::SafeBuffer.new
16
13
 
17
- input = prepend + input + append
18
- input += generate_error(attribute)
14
+ if input_group_required?(bootstrap)
15
+ prepend = attach_input(bootstrap, :prepend)
16
+ append = attach_input(bootstrap, :append)
19
17
 
20
- input = tag.div(input, class: input_group_classes(attribute, bootstrap))
21
- else
22
- input += generate_error(attribute)
23
- end
18
+ input = prepend + input + append
19
+ input += generate_error(attribute)
24
20
 
25
- input
21
+ input = tag.div(input, class: input_group_classes(attribute, bootstrap))
22
+ else
23
+ input += generate_error(attribute)
26
24
  end
27
25
 
28
- def input_group_classes(attribute, bootstrap)
29
- classes = Array("input-group") << bootstrap.additional_input_group_class
30
- if is_size_valid?(bootstrap)
31
- classes << "input-group-#{bootstrap.size}"
32
- end
33
- # Require `has-validation` class if field has errors.
34
- classes << "has-validation" if is_invalid?(attribute)
35
- classes.flatten.compact
36
- end
26
+ input
27
+ end
37
28
 
38
- def attach_input(bootstrap, key)
39
- tags = [*bootstrap.send(key)].map do |item|
40
- input_group_content(item)
41
- end
29
+ def input_group_classes(attribute, bootstrap)
30
+ classes = Array("input-group") << bootstrap.additional_input_group_class
31
+ if is_size_valid?(bootstrap)
32
+ classes << "input-group-#{bootstrap.size}"
33
+ end
34
+ # Require `has-validation` class if field has errors.
35
+ classes << "has-validation" if is_invalid?(attribute)
36
+ classes.flatten.compact
37
+ end
42
38
 
43
- ActiveSupport::SafeBuffer.new(tags.join)
39
+ def attach_input(bootstrap, key)
40
+ tags = [*bootstrap.send(key)].map do |item|
41
+ input_group_content(item)
44
42
  end
45
43
 
46
- def input_group_content(content)
47
- return content if /button|submit/.match?(content)
44
+ ActiveSupport::SafeBuffer.new(tags.join)
45
+ end
48
46
 
49
- tag.span(content.html_safe, class: "input-group-text")
50
- end
47
+ def input_group_content(content)
48
+ return content if /button|submit/.match?(content)
51
49
 
52
- def input_group_required?(bootstrap)
53
- [
54
- bootstrap.prepend,
55
- bootstrap.append
56
- ].any?(&:present?)
57
- end
50
+ tag.span(content.html_safe, class: "input-group-text")
51
+ end
58
52
 
59
- private :input_group_wrapper, :input_group_classes, :attach_input,
60
- :input_group_content, :input_group_required?
53
+ def input_group_required?(bootstrap)
54
+ [
55
+ bootstrap.prepend,
56
+ bootstrap.append
57
+ ].any?(&:present?)
61
58
  end
62
59
  end
63
60
  end
@@ -12,22 +12,8 @@ module RailsBootstrapForm
12
12
  inputs = ActiveSupport::SafeBuffer.new
13
13
 
14
14
  collection.each do |object|
15
- value = object.send(value_method)
16
-
17
- input_options = {
18
- bootstrap: {
19
- label_text: text_method.respond_to?(:call) ? text_method.call(object) : object.send(text_method),
20
- inline: (bootstrap.inline? || bootstrap.layout_inline?)
21
- },
22
- required: false,
23
- id: sanitized_tag_name(attribute, value)
24
- }.deep_merge!(options)
25
-
26
- if (checked = input_options[:checked])
27
- input_options[:checked] = collection_input_checked?(checked, object, value)
28
- end
29
-
30
- input_value = value_method.respond_to?(:call) ? value_method.call(object) : value
15
+ input_options = build_input_options(object, attribute, value_method, text_method, bootstrap, options)
16
+ input_value = resolve_input_value(object, value_method)
31
17
 
32
18
  inputs << yield(attribute, input_value, input_options)
33
19
  end
@@ -66,6 +52,36 @@ module RailsBootstrapForm
66
52
  end
67
53
  end
68
54
  end
55
+
56
+ private
57
+
58
+ def build_input_options(object, attribute, value_method, text_method, bootstrap, options)
59
+ input_options = {
60
+ bootstrap: {
61
+ label_text: resolve_label_text(text_method, object),
62
+ inline: (bootstrap.inline? || bootstrap.layout_inline?)
63
+ },
64
+ required: false,
65
+ id: sanitized_tag_name(attribute, object.send(value_method))
66
+ }.deep_merge!(options)
67
+
68
+ input_options[:checked] = resolve_checked_option(input_options[:checked], object, value_method)
69
+
70
+ input_options
71
+ end
72
+
73
+ def resolve_label_text(text_method, object)
74
+ text_method.respond_to?(:call) ? text_method.call(object) : object.send(text_method)
75
+ end
76
+
77
+ def resolve_input_value(object, value_method)
78
+ value_method.respond_to?(:call) ? value_method.call(object) : object.send(value_method)
79
+ end
80
+
81
+ def resolve_checked_option(checked_option, object, value_method)
82
+ return collection_input_checked?(checked_option, object, object.send(value_method)) if checked_option
83
+ false
84
+ end
69
85
  end
70
86
  end
71
87
  end
@@ -12,20 +12,10 @@ module RailsBootstrapForm
12
12
  bootstrap = bootstrap_form_options.scoped(options.delete(:bootstrap))
13
13
  return super if bootstrap.disabled?
14
14
 
15
- check_box_html = tag.div(class: choice_wrapper_classes(bootstrap)) do
16
- concat(bootstrap_check_box(attribute, checked_value, options, bootstrap))
17
- concat(help_text(attribute, bootstrap))
18
- concat(generate_error(attribute)) if is_invalid?(attribute)
19
- end
15
+ check_box_html = build_check_box_html(attribute, checked_value, bootstrap, options)
20
16
 
21
17
  if bootstrap.wrapper
22
- tag.div(**field_wrapper_options(bootstrap)) do
23
- if bootstrap.layout_horizontal?
24
- tag.div(class: choice_container_classes(bootstrap)) { check_box_html }
25
- else
26
- check_box_html
27
- end
28
- end
18
+ build_wrapped_check_box_html(bootstrap, check_box_html)
29
19
  else
30
20
  check_box_html
31
21
  end
@@ -12,20 +12,10 @@ module RailsBootstrapForm
12
12
  bootstrap = bootstrap_form_options.scoped(options.delete(:bootstrap))
13
13
  return super if bootstrap.disabled?
14
14
 
15
- radio_button_html = tag.div(class: choice_wrapper_classes(bootstrap)) do
16
- concat(bootstrap_radio_button(attribute, value, options, bootstrap))
17
- concat(help_text(attribute, bootstrap))
18
- concat(generate_error(attribute)) if is_invalid?(attribute)
19
- end
15
+ radio_button_html = build_radio_button_html(attribute, value, bootstrap, options)
20
16
 
21
17
  if bootstrap.wrapper
22
- tag.div(**field_wrapper_options(bootstrap)) do
23
- if bootstrap.layout_horizontal?
24
- tag.div(class: choice_container_classes(bootstrap)) { radio_button_html }
25
- else
26
- radio_button_html
27
- end
28
- end
18
+ build_wrapped_radio_button_html(bootstrap, radio_button_html)
29
19
  else
30
20
  radio_button_html
31
21
  end
@@ -3,6 +3,6 @@
3
3
  # -*- warn_indent: true -*-
4
4
 
5
5
  module RailsBootstrapForm
6
- VERSION = "0.9.7".freeze
6
+ VERSION = "0.9.8".freeze
7
7
  REQUIRED_RAILS_VERSION = "~> 7.0".freeze
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_bootstrap_form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harshal LADHE (shivam091)
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-26 00:00:00.000000000 Z
11
+ date: 2023-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: generator_spec
@@ -60,6 +60,7 @@ executables: []
60
60
  extensions: []
61
61
  extra_rdoc_files: []
62
62
  files:
63
+ - ".codeclimate.yml"
63
64
  - ".rspec"
64
65
  - CHANGELOG.md
65
66
  - CODE_OF_CONDUCT.md