rails_bootstrap_form 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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