Skip to content

Commit

Permalink
Reduce method complexity of button, error methods , and field wrapp…
Browse files Browse the repository at this point in the history
…er options
  • Loading branch information
shivam091 committed Jul 1, 2023
1 parent ebf1dc9 commit ba8cf55
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 54 deletions.
28 changes: 17 additions & 11 deletions lib/rails_bootstrap_form/field_wrapper_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

module RailsBootstrapForm
module FieldWrapperBuilder

private

def field_wrapper_builder(attribute, bootstrap, options, html_options = nil, &block)
field_options = field_css_options(attribute, bootstrap, options, html_options.try(:symbolize_keys!))

Expand Down Expand Up @@ -72,18 +75,11 @@ def field_wrapper_default_class(bootstrap)
def field_css_options(attribute, bootstrap, options, html_options)
css_options = (html_options || options)

field_classes = Array(bootstrap.field_class) << [bootstrap.additional_field_class || css_options[:class]]
field_classes << "is-invalid" if is_invalid?(attribute)
if is_size_valid?(bootstrap)
field_classes << "#{bootstrap.field_class}-#{bootstrap.size}"
end
field_classes = build_field_classes(attribute, bootstrap, css_options)

css_options[:class] = field_classes.flatten.compact
css_options.merge!(required_field_options(attribute, options))

if placeholder_required?(bootstrap)
css_options[:placeholder] ||= label_text(attribute, bootstrap)
end
add_placeholder_if_required!(css_options, attribute, bootstrap)

css_options
end
Expand All @@ -96,11 +92,21 @@ def floating_label_classes(attribute)
classes
end

def build_field_classes(attribute, bootstrap, css_options)
field_classes = Array(bootstrap.field_class) <<
field_classes << [bootstrap.additional_field_class || css_options[:class]]
field_classes << "is-invalid" if is_invalid?(attribute)
field_classes << "#{bootstrap.field_class}-#{bootstrap.size}" if is_size_valid?(bootstrap)
field_classes
end

def placeholder_required?(bootstrap)
(bootstrap.floating? && !bootstrap.layout_horizontal?) || bootstrap.layout_inline?
end

private :field_wrapper, :field_wrapper_classes, :field_wrapper_default_class,
:field_css_options, :floating_label_classes
def add_placeholder_if_required!(css_options, attribute, bootstrap)
css_options[:placeholder] ||= label_text(attribute, bootstrap) if placeholder_required?(bootstrap)
css_options
end
end
end
48 changes: 33 additions & 15 deletions lib/rails_bootstrap_form/helpers/buttons.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,17 @@ module Helpers
module Buttons
extend ActiveSupport::Concern

def self.included(base_class)
included do
def button(value, options, &block)
bootstrap = bootstrap_form_options.scoped(options.delete(:bootstrap))
value, options = extract_button_value_and_options(value, options)

value, options = nil, value.merge(options) if value.is_a?(Hash)
add_button_css_classes!(options, bootstrap)

add_css_class!(options, "btn")
add_css_class!(options, button_variant_class(options))
button_html = render_button_html(value, options, bootstrap, &block)
button_html = wrap_button_html(button_html, bootstrap)

button_html = if (bootstrap.render_as_button? || block)
button_tag(value, options, &block)
else
submit(value, options)
end

if bootstrap.layout_inline?
tag.div(class: "col-12") { button_html }
else
button_html
end
button_html
end

def secondary(value = nil, options = {}, &block)
Expand All @@ -52,6 +43,33 @@ def button_variant_class(options)
else ""
end
end

def extract_button_value_and_options(value, options)
return [nil, value.merge(options)] if value.is_a?(Hash)

[value, options]
end

def add_button_css_classes!(options, bootstrap)
add_css_class!(options, "btn")
add_css_class!(options, button_variant_class(options))
end

def render_button_html(value, options, bootstrap, &block)
if bootstrap.render_as_button? || block
button_tag(value, options, &block)
else
submit(value, options)
end
end

def wrap_button_html(button_html, bootstrap)
if bootstrap.layout_inline?
tag.div(class: "col-12") { button_html }
else
button_html
end
end
end
end
end
45 changes: 25 additions & 20 deletions lib/rails_bootstrap_form/helpers/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,10 @@ module Errors
private

def is_invalid?(attribute)
(attribute && object.respond_to?(:errors) && object.errors[attribute].any?) ||
(attribute && object.respond_to?(:errors) && has_attribute_error?(attribute)) ||
has_association_error?(attribute)
end

# def input_with_error(attribute, &block)
# input = capture(&block)
# input << generate_error(attribute)
# input
# end

def generate_error(attribute)
if is_invalid?(attribute)
error_text = error_messages(attribute)
Expand All @@ -29,23 +23,41 @@ def generate_error(attribute)
end
end

def error_messages(attribute)
messages = Array(attribute_error_messages(attribute))
messages << associated_error_messages(attribute)

messages.flatten.to_sentence
end

def has_attribute_error?(attribute)
attribute_error_messages(attribute).any?
end

def has_association_error?(attribute)
object.class.try(:reflections)&.any? do |association_name, association|
has_error_for_association?(attribute, association_name)
has_errors_on_association?(attribute, association_name)
end
end

def error_messages(attribute)
messages = object.errors[attribute]
def has_errors_on_association?(attribute, association_name)
return false unless is_belongs_to_association?(object.class.reflections[association_name])
return false unless is_association_same?(attribute, object.class.reflections[association_name])

object.errors[association_name].any?
end

def attribute_error_messages(attribute)
object.errors[attribute]
end

object.class.try(:reflections)&.each do |association_name, association|
def associated_error_messages(attribute)
object.class.try(:reflections)&.each_with_object([]) do |(association_name, association), messages|
next unless is_belongs_to_association?(association)
next unless is_association_same?(attribute, association)

messages << object.errors[association_name]
end

messages.flatten.to_sentence
end

def is_belongs_to_association?(association)
Expand All @@ -55,13 +67,6 @@ def is_belongs_to_association?(association)
def is_association_same?(attribute, association)
(association.foreign_key == attribute.to_s)
end

def has_error_for_association?(attribute, association_name)
return false unless is_belongs_to_association?(object.class.reflections[association_name])
return false unless is_association_same?(attribute, object.class.reflections[association_name])

object.errors[association_name].any?
end
end
end
end
16 changes: 8 additions & 8 deletions spec/rails_bootstrap_form/special_form_class_models_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,19 @@ def self.model_name
}
})
expected = <<~HTML
<div class="mb-3">
<div class="field_with_errors">
<form role="form" novalidate="novalidate" action="/test" accept-charset="UTF-8" method="post">
<div class="mb-3">
<label class="form-label required is-invalid" for="admin_user_password">Password</label>
</div>
<div class="field_with_errors">
<input class="form-control is-invalid" aria-required="true" required="required" type="text" name="admin_user[password]" id="admin_user_password" />
<div class="invalid-feedback">can't be blank and </div>
<div class="form-text text-muted">A good password should be at least six characters long</div>
</div>
<div class="invalid-feedback">can't be blank</div>
<div class="form-text text-muted">A good password should be at least six characters long</div>
</div>
</form>
HTML

actual = form_builder.text_field(:password)
actual = bootstrap_form_with(model: admin_user, url: "/test") do |form|
concat(form.text_field(:password))
end

expect(actual).to match_html(expected)
end
Expand Down

0 comments on commit ba8cf55

Please sign in to comment.