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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
# frozen_string_literal: true
module ClientSideValidations
module ActionView
module Helpers
module FormBuilder
def self.prepended(base)
selectors = base.field_helpers - %i[label check_box checkbox radio_button fields_for fields hidden_field file_field]
selectors.each do |selector|
base.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
# Cannot call super here, rewrite all
def #{selector}(method, options = {}) # def text_field(method, options = {})
build_validation_options(method, options) # build_validation_options(method, options)
options.delete(:validate) # options.delete(:validate)
@template.send( # @template.send(
#{selector.inspect}, # "text_field",
@object_name, # @object_name,
method, # method,
objectify_options(options)) # objectify_options(options))
end # end
RUBY_EVAL
end
base.class_eval do
alias_method :text_area, :textarea if ::ActionView::Helpers::FormBuilder.field_helpers.include?(:textarea)
end
end
def initialize(object_name, object, template, options)
super
@options[:validators] = { object => {} }
end
def client_side_form_settings(_options, form_helper)
{
type: self.class.name,
input_tag: error_field(form_helper, :span, 'input_tag'),
label_tag: error_field(form_helper, :label, 'label_tag')
}
end
def validate(*attrs)
options = attrs.pop if attrs.last.is_a?(Hash)
(attrs.presence || @object._validators.keys).each do |attr|
build_validation_options(attr, validate: options)
end
nil
end
def check_box(method, options = {}, checked_value = '1', unchecked_value = '0')
build_validation_options(method, options)
options.delete(:validate)
super
end
alias checkbox check_box if ::ActionView::Helpers::FormBuilder.field_helpers.include?(:checkbox)
%i[collection_check_boxes collection_radio_buttons].each do |method_name|
define_method method_name do |method, collection, value_method, text_method, options = {}, html_options = {}, &block|
build_validation_options(method, html_options.merge(name: options[:name]))
html_options.delete(:validate)
super(method, collection, value_method, text_method, options, html_options, &block)
end
end
if ::ActionView::Helpers::FormBuilder.public_method_defined?(:collection_checkboxes)
alias collection_checkboxes collection_check_boxes
end
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
build_validation_options(method, html_options.merge(name: options[:name]))
html_options.delete(:validate)
super
end
def fields_for(record_name, record_object = nil, fields_options = {}, &)
if record_object.is_a?(Hash) && record_object.extractable_options?
fields_options = record_object
record_object = nil
end
fields_options[:validate] ||= @options[:validate] if @options[:validate] && !fields_options.key?(:validate)
super
end
def fields(scope = nil, model: nil, **options, &block)
options[:validate] ||= @options[:validate] if @options[:validate] && !options.key?(:validate)
super
end
def file_field(method, options = {})
build_validation_options(method, options)
options.delete(:validate)
super
end
def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
build_validation_options(method, html_options.merge(name: options[:name]))
html_options.delete(:validate)
super
end
def radio_button(method, tag_value, options = {})
build_validation_options(method, options)
options.delete(:validate)
super
end
def select(method, choices = nil, options = {}, html_options = {}, &)
build_validation_options(method, html_options.merge(name: options[:name]))
html_options.delete(:validate)
super
end
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
build_validation_options(method, html_options.merge(name: options[:name]))
html_options.delete(:validate)
super
end
private
def error_field(form_helper, tag, id)
form_helper.instance_exec form_helper.content_tag(tag, nil, id: id),
Struct.new(:error_message, :tag_id).new([], ''),
&form_helper.class.field_error_proc
end
def build_validation_options(method, options = {})
return unless @options[:validate]
index = @default_options[:index].present? ? "[#{@default_options[:index]}]" : ''
child_index = @options[:child_index] ? "(\\d+|#{Regexp.escape(@options[:child_index].to_s)})" : '\\d+'
name = options[:name] || "#{@object_name}#{index}[#{method}]"
name = name.to_s.gsub(/_attributes\]\[#{child_index}\]/, '_attributes][]')
name << '[]' if options[:multiple]
@options[:validators][@object][method] = { name: name, options: options[:validate] }
end
end
end
end
end
|