Skip to content

Commit

Permalink
Improve form helper
Browse files Browse the repository at this point in the history
  • Loading branch information
tagliala committed Jan 22, 2017
1 parent 10f2f2e commit f428709
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 61 deletions.
4 changes: 2 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ AllCops:
TargetRubyVersion: 2.2

Metrics/AbcSize:
Max: 37.23 # TODO: Lower to 15
Max: 33.79 # TODO: Lower to 15

Metrics/BlockLength:
Exclude:
Expand All @@ -23,7 +23,7 @@ Metrics/LineLength:
Enabled: false

Metrics/MethodLength:
Max: 25
Max: 20
Exclude:
- 'test/**/*'

Expand Down
93 changes: 34 additions & 59 deletions lib/client_side_validations/action_view/form_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,44 @@ class Error < StandardError
end

def form_for(record, options = {}, &block)
raise ArgumentError, 'Missing block' unless block_given?
if options[:validate]
return super unless options[:validate]

# Always turn off HTML5 Validations
options[:html] ||= {}
options[:html][:novalidate] = 'novalidate'
# Always turn off HTML5 Validations
options[:html] ||= {}
options[:html][:novalidate] = 'novalidate'

case record
when String, Symbol
raise ClientSideValidations::ActionView::Helpers::FormHelper::Error, 'Using form_for(:name, @resource) is not supported with ClientSideValidations. Please use form_for(@resource, as: :name) instead.'
else
object = record.is_a?(Array) ? record.last : record
object_name = options[:as] || model_name_from_record_or_class(object).param_key
end
case record
when String, Symbol
raise ClientSideValidations::ActionView::Helpers::FormHelper::Error, 'Using form_for(:name, @resource) is not supported with ClientSideValidations. Please use form_for(@resource, as: :name) instead.'
else
object = record.is_a?(Array) ? record.last : record
object_name = options[:as] || model_name_from_record_or_class(object).param_key
end

@validators = {}

# Order matters here. Rails mutates the options object
html_id = options[:html][:id] if options[:html]
form = super(record, options, &block)
options[:id] = html_id if html_id

build_bound_validators options
builder = instantiate_builder(object_name, object, options) if object_name && object
script = client_side_form_settings(object, options, builder)
# Order matters here. Rails mutates the `options` object
form = super

# Because of the load order requirement above this sub is necessary
# Would be nice to not do this
script = insert_validators_into_script(script)
build_bound_validators! options
builder = instantiate_builder(object_name, object, options)
script = client_side_form_settings(options, builder)

# rubocop:disable OutputSafety
# TODO: check if html_safe is really needed here
if assign_script_to_content_for(options[:validate], script)
form.html_safe
form
else
"#{form}#{script}".html_safe
[form, script].join
end
# rubocop:enable OutputSafety
end

def assign_script_to_content_for(name, script)
return false unless name && name != true

# rubocop:disable OutputSafety
# TODO: check if html_safe is really needed here
return unless name && name != true
content_for name, script.html_safe
true
# rubocop:enable OutputSafety

true
end

def apply_form_for_options!(record, object, options)
Expand All @@ -63,15 +53,19 @@ def apply_form_for_options!(record, object, options)
end

def fields_for(record_or_name_or_array, record_object = nil, options = {}, &block)
# Order matters here. Rails mutates the `options` object
output = super
build_bound_validators options

build_bound_validators! options

output
end

private

def build_bound_validators(options)
def build_bound_validators!(options)
return unless @validators

options[:validators].each do |key, value|
if @validators.key?(key)
@validators[key].merge! value
Expand All @@ -81,17 +75,6 @@ def build_bound_validators(options)
end
end

def insert_validators_into_script(script)
# There is probably a more performant way of doing this
# But using String#sub has some issues. Undocumented "features"
if script
script = script.split(/"validator_hash"/)
script = "#{script[0]}#{construct_validators.to_json}#{script[1]}"
end

script
end

def construct_validators
@validators.each_with_object({}) do |object_opts, validator_hash|
option_hash = object_opts[1].each_with_object({}) do |attr, result|
Expand All @@ -113,27 +96,19 @@ def construct_validators
end
end

def client_side_form_settings(object, options, builder)
return unless options[:validate]
var_name =
if options[:id]
options[:id]
elsif object.respond_to?(:persisted?) && object.persisted?
options[:as] ? "edit_#{options[:as]}" : [options[:namespace], dom_id(object, :edit)].compact.join('_'.freeze)
else
options[:as] ? "new_#{options[:as]}" : [options[:namespace], dom_id(object)].compact.join('_'.freeze)
end
def client_side_form_settings(options, builder)
patterns = { numericality: "/^(-|\\+)?(?:\\d+|\\d{1,3}(?:\\#{number_format[:delimiter]}\\d{3})+)(?:\\#{number_format[:separator]}\\d*)?$/" }

javascript_tag "if(window.ClientSideValidations===undefined)window.ClientSideValidations={};window.ClientSideValidations.disabled_validators=#{ClientSideValidations::Config.disabled_validators.to_json};window.ClientSideValidations.number_format=#{number_format.to_json};if(window.ClientSideValidations.patterns===undefined)window.ClientSideValidations.patterns = {};window.ClientSideValidations.patterns.numericality=#{patterns[:numericality]};#{"if(window.ClientSideValidations.remote_validators_prefix===undefined)window.ClientSideValidations.remote_validators_prefix='#{ClientSideValidations::Config.root_path.sub(%r{/+\Z}, '')}';" if ClientSideValidations::Config.root_path.present?}if(window.ClientSideValidations.forms===undefined)window.ClientSideValidations.forms={};window.ClientSideValidations.forms['#{options[:html]['id']}'] = #{builder.client_side_form_settings(options, self).merge(validators: construct_validators).to_json};"
end

number_format =
def number_format
@number_format ||=
if ClientSideValidations::Config.number_format_with_locale && defined?(I18n)
I18n.t('number.format').slice(:separator, :delimiter)
else
{ separator: '.', delimiter: ',' }
end

patterns = { numericality: "/^(-|\\+)?(?:\\d+|\\d{1,3}(?:\\#{number_format[:delimiter]}\\d{3})+)(?:\\#{number_format[:separator]}\\d*)?$/" }

javascript_tag "if(window.ClientSideValidations===undefined)window.ClientSideValidations={};window.ClientSideValidations.disabled_validators=#{ClientSideValidations::Config.disabled_validators.to_json};window.ClientSideValidations.number_format=#{number_format.to_json};if(window.ClientSideValidations.patterns===undefined)window.ClientSideValidations.patterns = {};window.ClientSideValidations.patterns.numericality=#{patterns[:numericality]};#{"if(window.ClientSideValidations.remote_validators_prefix===undefined)window.ClientSideValidations.remote_validators_prefix='#{ClientSideValidations::Config.root_path.sub(%r{/+\Z}, '')}';" if ClientSideValidations::Config.root_path.present?}if(window.ClientSideValidations.forms===undefined)window.ClientSideValidations.forms={};window.ClientSideValidations.forms['#{var_name}'] = #{builder.client_side_form_settings(options, self).merge(validators: 'validator_hash').to_json};"
end
end
end
Expand Down

0 comments on commit f428709

Please sign in to comment.