File: validation.rb

package info (click to toggle)
ruby-bootstrap-form 5.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 512 kB
  • sloc: ruby: 1,350; makefile: 4
file content (90 lines) | stat: -rw-r--r-- 2,932 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# frozen_string_literal: true

module BootstrapForm
  module Components
    module Validation
      extend ActiveSupport::Concern

      private

      def error?(name)
        name && object.respond_to?(:errors) && (object.errors[name].any? || association_error?(name))
      end

      def association_error?(name)
        object.class.try(:reflections)&.any? do |association_name, a|
          next unless a.is_a?(ActiveRecord::Reflection::BelongsToReflection)
          next unless a.foreign_key == name.to_s

          object.errors[association_name].any?
        end
      end

      def required_attribute?(obj, attribute)
        return false unless obj && attribute

        target = obj.instance_of?(Class) ? obj : obj.class
        return false unless target.respond_to? :validators_on

        presence_validators?(target, obj, attribute) || required_association?(target, obj, attribute)
      end

      def required_association?(target, object, attribute)
        target.try(:reflections)&.any? do |name, a|
          next unless a.is_a?(ActiveRecord::Reflection::BelongsToReflection)
          next unless a.foreign_key == attribute.to_s

          presence_validators?(target, object, name)
        end
      end

      def presence_validators?(target, object, attribute)
        target.validators_on(attribute).select { |v| presence_validator?(v.class) }.any? do |validator|
          if_option = validator.options[:if]
          unless_opt = validator.options[:unless]
          (!if_option || call_with_self(object, if_option)) && (!unless_opt || !call_with_self(object, unless_opt))
        end
      end

      def call_with_self(object, proc)
        proc = object.method(proc) if proc.is_a? Symbol
        object.instance_exec(*[(object if proc.arity >= 1)].compact, &proc)
      end

      def presence_validator?(validator_class)
        validator_class == ActiveModel::Validations::PresenceValidator ||
          (defined?(ActiveRecord::Validations::PresenceValidator) &&
            validator_class == ActiveRecord::Validations::PresenceValidator)
      end

      def inline_error?(name)
        error?(name) && inline_errors
      end

      def generate_error(name)
        return unless inline_error?(name)

        help_text = get_error_messages(name)
        help_klass = "invalid-feedback"
        help_tag = :div

        content_tag(help_tag, help_text, class: help_klass)
      end

      # rubocop:disable Metrics/AbcSize
      def get_error_messages(name)
        object.class.try(:reflections)&.each do |association_name, a|
          next unless a.is_a?(ActiveRecord::Reflection::BelongsToReflection)
          next unless a.foreign_key == name.to_s

          object.errors[association_name].each do |error|
            object.errors.add(name, error)
          end
        end

        safe_join(object.errors[name], ", ")
      end
      # rubocop:enable Metrics/AbcSize
    end
  end
end