rails4_client_side_validations 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -0
- data/lib/generators/rails4_client_side_validations/copy_assets_generator.rb +58 -0
- data/lib/generators/rails4_client_side_validations/install_generator.rb +22 -0
- data/lib/generators/templates/client_side_validations/initializer.rb +20 -0
- data/lib/rails4_client_side_validations.rb +13 -0
- data/lib/rails4_client_side_validations/action_view.rb +14 -0
- data/lib/rails4_client_side_validations/action_view/form_builder.rb +105 -0
- data/lib/rails4_client_side_validations/action_view/form_helper.rb +139 -0
- data/lib/rails4_client_side_validations/action_view/form_tag_helper.rb +12 -0
- data/lib/rails4_client_side_validations/active_model.rb +143 -0
- data/lib/rails4_client_side_validations/active_model/absence.rb +10 -0
- data/lib/rails4_client_side_validations/active_model/acceptance.rb +10 -0
- data/lib/rails4_client_side_validations/active_model/exclusion.rb +27 -0
- data/lib/rails4_client_side_validations/active_model/format.rb +31 -0
- data/lib/rails4_client_side_validations/active_model/inclusion.rb +26 -0
- data/lib/rails4_client_side_validations/active_model/length.rb +26 -0
- data/lib/rails4_client_side_validations/active_model/numericality.rb +42 -0
- data/lib/rails4_client_side_validations/active_model/presence.rb +10 -0
- data/lib/rails4_client_side_validations/active_record.rb +12 -0
- data/lib/rails4_client_side_validations/active_record/middleware.rb +59 -0
- data/lib/rails4_client_side_validations/active_record/uniqueness.rb +29 -0
- data/lib/rails4_client_side_validations/config.rb +13 -0
- data/lib/rails4_client_side_validations/core_ext.rb +3 -0
- data/lib/rails4_client_side_validations/core_ext/range.rb +10 -0
- data/lib/rails4_client_side_validations/core_ext/regexp.rb +13 -0
- data/lib/rails4_client_side_validations/engine.rb +6 -0
- data/lib/rails4_client_side_validations/files.rb +8 -0
- data/lib/rails4_client_side_validations/generators.rb +12 -0
- data/lib/rails4_client_side_validations/generators/rails_validations.rb +15 -0
- data/lib/rails4_client_side_validations/middleware.rb +120 -0
- data/lib/rails4_client_side_validations/version.rb +3 -0
- data/vendor/assets/javascripts/rails.validations.js +639 -0
- metadata +40 -9
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
It's modifed version of [client_side_validations](https://github.com/bcardarella/client_side_validations.git), which supports Rails 4
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Rails4ClientSideValidations
|
2
|
+
module Generators
|
3
|
+
class CopyAssetsGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
def copy_javascript_asset
|
6
|
+
if self.class == CopyAssetsGenerator || !asset_pipeline_enabled?
|
7
|
+
assets.each do |asset|
|
8
|
+
source_paths << asset[:path]
|
9
|
+
copy_file asset[:file], "#{asset_directory}/#{asset[:file]}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def self.asset_directory
|
17
|
+
if asset_pipeline_enabled?
|
18
|
+
"app#{Rails.configuration.assets.prefix}/javascripts"
|
19
|
+
else
|
20
|
+
'public/javascripts'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def asset_directory
|
25
|
+
CopyAssetsGenerator.asset_directory
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.assets
|
29
|
+
Assets
|
30
|
+
end
|
31
|
+
|
32
|
+
def assets
|
33
|
+
CopyAssetsGenerator.assets
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.asset_file_names
|
37
|
+
assets.map { |asset| asset[:file] }.join(', ')
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.asset_pipeline_enabled?
|
41
|
+
if Rails.application
|
42
|
+
(Rails.configuration.respond_to?(:assets) ? (Rails.configuration.assets || {}) : {})[:enabled]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def asset_pipeline_enabled?
|
47
|
+
self.class.asset_pipeline_enabled?
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.installation_message
|
51
|
+
"Copies #{asset_file_names} to #{asset_directory}"
|
52
|
+
end
|
53
|
+
|
54
|
+
desc installation_message
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'generators/rails4_client_side_validations/copy_assets_generator'
|
2
|
+
|
3
|
+
module Rails4ClientSideValidations
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < CopyAssetsGenerator
|
6
|
+
|
7
|
+
def copy_initializer
|
8
|
+
source_paths << File.expand_path('../../templates/rails4_client_side_validations', __FILE__)
|
9
|
+
copy_file 'initializer.rb', 'config/initializers/rails4_client_side_validations.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def self.installation_message
|
15
|
+
"Copies initializer into config/initializers and #{super.downcase}"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc installation_message
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# ClientSideValidations Initializer
|
2
|
+
|
3
|
+
# Uncomment to disable uniqueness validator, possible security issue
|
4
|
+
# ClientSideValidations::Config.disabled_validators = [:uniqueness]
|
5
|
+
|
6
|
+
# Uncomment to validate number format with current I18n locale
|
7
|
+
# ClientSideValidations::Config.number_format_with_locale = true
|
8
|
+
|
9
|
+
# Uncomment to set a custom application scope
|
10
|
+
# ClientSideValidations::Config.root_path = '/your/application/scope'
|
11
|
+
|
12
|
+
# Uncomment the following block if you want each input field to have the validation messages attached.
|
13
|
+
# ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
|
14
|
+
# unless html_tag =~ /^<label/
|
15
|
+
# %{<div class="field_with_errors">#{html_tag}<label for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</label></div>}.html_safe
|
16
|
+
# else
|
17
|
+
# %{<div class="field_with_errors">#{html_tag}</div>}.html_safe
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Rails4ClientSideValidations
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'rails4_client_side_validations/config'
|
5
|
+
require 'rails4_client_side_validations/active_model' if defined?(::ActiveModel)
|
6
|
+
require 'rails4_client_side_validations/active_record' if defined?(::ActiveRecord)
|
7
|
+
require 'rails4_client_side_validations/action_view' if defined?(::ActionView)
|
8
|
+
if defined?(::Rails)
|
9
|
+
require 'rails4_client_side_validations/generators'
|
10
|
+
require 'rails4_client_side_validations/middleware'
|
11
|
+
require 'rails4_client_side_validations/engine'
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Rails4ClientSideValidations::ActionView
|
2
|
+
module Helpers
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'rails4_client_side_validations/core_ext'
|
7
|
+
require 'rails4_client_side_validations/action_view/form_helper'
|
8
|
+
require 'rails4_client_side_validations/action_view/form_tag_helper'
|
9
|
+
require 'rails4_client_side_validations/action_view/form_builder'
|
10
|
+
|
11
|
+
ActionView::Base.send(:include, Rails4ClientSideValidations::ActionView::Helpers::FormHelper)
|
12
|
+
ActionView::Base.send(:include, Rails4ClientSideValidations::ActionView::Helpers::FormTagHelper)
|
13
|
+
ActionView::Helpers::FormBuilder.send(:include, Rails4ClientSideValidations::ActionView::Helpers::FormBuilder)
|
14
|
+
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Rails4ClientSideValidations::ActionView::Helpers
|
2
|
+
module FormBuilder
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
(base.field_helpers.map(&:to_s) - %w(apply_form_for_options! label check_box radio_button fields_for hidden_field)).each do |selector|
|
6
|
+
base.class_eval <<-RUBY_EVAL
|
7
|
+
def #{selector}_with_rails4_client_side_validations(method, options = {})
|
8
|
+
build_validation_options(method, options)
|
9
|
+
options.delete(:validate)
|
10
|
+
#{selector}_without_rails4_client_side_validations(method, options)
|
11
|
+
end
|
12
|
+
RUBY_EVAL
|
13
|
+
|
14
|
+
base.class_eval { alias_method_chain selector, :rails4_client_side_validations }
|
15
|
+
end
|
16
|
+
|
17
|
+
base.class_eval do
|
18
|
+
alias_method_chain :initialize, :rails4_client_side_validations
|
19
|
+
alias_method_chain :fields_for, :rails4_client_side_validations
|
20
|
+
alias_method_chain :check_box, :rails4_client_side_validations
|
21
|
+
alias_method_chain :radio_button, :rails4_client_side_validations
|
22
|
+
alias_method_chain :select, :rails4_client_side_validations
|
23
|
+
alias_method_chain :collection_select, :rails4_client_side_validations
|
24
|
+
alias_method_chain :grouped_collection_select, :rails4_client_side_validations
|
25
|
+
alias_method_chain :time_zone_select, :rails4_client_side_validations
|
26
|
+
|
27
|
+
def client_side_form_settings(options, form_helper)
|
28
|
+
{
|
29
|
+
:type => self.class.to_s,
|
30
|
+
:input_tag => form_helper.class.field_error_proc.call(%{<span id="input_tag" />}, Struct.new(:error_message, :tag_id).new([], "")),
|
31
|
+
:label_tag => form_helper.class.field_error_proc.call(%{<label id="label_tag" />}, Struct.new(:error_message, :tag_id).new([], ""))
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate(*attrs)
|
38
|
+
options = attrs.pop if attrs.last.is_a?(Hash)
|
39
|
+
(attrs.present? ? attrs : @object._validators.keys).each do |attr|
|
40
|
+
build_validation_options(attr, :validate => options)
|
41
|
+
end
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize_with_rails4_client_side_validations(object_name, object, template, options, proc=nil)
|
46
|
+
initialize_without_rails4_client_side_validations(object_name, object, template, options, proc)
|
47
|
+
@options[:validators] = { object => {} }
|
48
|
+
end
|
49
|
+
|
50
|
+
def fields_for_with_rails4_client_side_validations(record_or_name_or_array, *args, &block)
|
51
|
+
options = args.extract_options!
|
52
|
+
options[:validate] ||= @options[:validate] if @options[:validate] && !options.key?(:validate)
|
53
|
+
fields_for_without_rails4_client_side_validations(record_or_name_or_array, *(args << options), &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def check_box_with_rails4_client_side_validations(method, options = {}, checked_value = "1", unchecked_value = "0")
|
57
|
+
build_validation_options(method, options)
|
58
|
+
options.delete(:validate)
|
59
|
+
check_box_without_rails4_client_side_validations(method, options, checked_value, unchecked_value)
|
60
|
+
end
|
61
|
+
|
62
|
+
def radio_button_with_rails4_client_side_validations(method, tag_value, options = {})
|
63
|
+
build_validation_options(method, options)
|
64
|
+
options.delete(:validate)
|
65
|
+
radio_button_without_rails4_client_side_validations(method, tag_value, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def select_with_rails4_client_side_validations(method, choices, options = {}, html_options = {})
|
69
|
+
build_validation_options(method, html_options.merge(:name => options[:name]))
|
70
|
+
html_options.delete(:validate)
|
71
|
+
select_without_rails4_client_side_validations(method, choices, options, html_options)
|
72
|
+
end
|
73
|
+
|
74
|
+
def collection_select_with_rails4_client_side_validations(method, collection, value_method, text_method, options = {}, html_options = {})
|
75
|
+
build_validation_options(method, html_options.merge(:name => options[:name]))
|
76
|
+
html_options.delete(:validate)
|
77
|
+
collection_select_without_rails4_client_side_validations(method, collection, value_method, text_method, options, html_options)
|
78
|
+
end
|
79
|
+
|
80
|
+
def grouped_collection_select_with_rails4_client_side_validations(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
|
81
|
+
build_validation_options(method, html_options.merge(:name => options[:name]))
|
82
|
+
html_options.delete(:validate)
|
83
|
+
grouped_collection_select_without_rails4_client_side_validations(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
|
84
|
+
end
|
85
|
+
|
86
|
+
def time_zone_select_with_rails4_client_side_validations(method, priority_zones = nil, options = {}, html_options = {})
|
87
|
+
build_validation_options(method, html_options.merge(:name => options[:name]))
|
88
|
+
html_options.delete(:validate)
|
89
|
+
time_zone_select_without_rails4_client_side_validations(method, priority_zones, options, html_options)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def build_validation_options(method, options = {})
|
95
|
+
if @options[:validate]
|
96
|
+
index = @default_options[:index].present? ? "[#{@default_options[:index]}]" : ''
|
97
|
+
name = options[:name] || "#{@object_name}#{index}[#{method}]"
|
98
|
+
child_index = @options[:child_index] ? "(\\d+|#{Regexp.escape(@options[:child_index].to_s)})" : "\\d+"
|
99
|
+
name = name.to_s.gsub(/_attributes\]\[#{child_index}\]/, '_attributes][]')
|
100
|
+
name = "#{name}#{options[:multiple] ? "[]" : nil}"
|
101
|
+
@options[:validators][@object][method] = { :name => name, :options => options[:validate] }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module Rails4ClientSideValidations::ActionView::Helpers
|
2
|
+
module FormHelper
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
def form_for(record, *args, &block)
|
6
|
+
raise ArgumentError, "Missing block" unless block_given?
|
7
|
+
options = args.extract_options!
|
8
|
+
if options[:validate]
|
9
|
+
|
10
|
+
# Always turn off HTML5 Validations
|
11
|
+
options[:html] ||= {}
|
12
|
+
options[:html][:novalidate] = 'novalidate'
|
13
|
+
|
14
|
+
case record
|
15
|
+
when String, Symbol
|
16
|
+
raise Rails4ClientSideValidations::ActionView::Helpers::FormHelper::Error, 'Using form_for(:name, @resource) is not supported with ClientSideValidations. Please use form_for(@resource, :as => :name) instead.'
|
17
|
+
else
|
18
|
+
object = record.is_a?(Array) ? record.last : record
|
19
|
+
object_name = options[:as] || model_name_from_record_or_class(object).param_key
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
@validators = {}
|
24
|
+
|
25
|
+
# Order matters here. Rails mutates the options object
|
26
|
+
html_id = options[:html][:id] if options[:html]
|
27
|
+
form = super(record, *(args << options), &block)
|
28
|
+
options[:id] = html_id if html_id
|
29
|
+
|
30
|
+
process_validators options
|
31
|
+
builder = instantiate_builder(object_name, object, options) if object_name and object
|
32
|
+
|
33
|
+
script = client_side_form_settings(object, options, builder)
|
34
|
+
|
35
|
+
# Because of the load order requirement above this sub is necessary
|
36
|
+
# Would be nice to not do this
|
37
|
+
script = insert_validators_into_script(script)
|
38
|
+
|
39
|
+
if assign_script_to_content_for(options[:validate], script)
|
40
|
+
form.html_safe
|
41
|
+
else
|
42
|
+
"#{form}#{script}".html_safe
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def assign_script_to_content_for(name, script)
|
47
|
+
if name && name != true
|
48
|
+
content_for(name) { script.html_safe }
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def apply_form_for_options!(object_or_array, object, options)
|
54
|
+
super
|
55
|
+
options[:html][:validate] = true if options[:validate]
|
56
|
+
end
|
57
|
+
|
58
|
+
def fields_for(record_or_name_or_array, record_object = nil, options = {}, &block)
|
59
|
+
output = super
|
60
|
+
process_validators options
|
61
|
+
output
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def process_validators(options)
|
67
|
+
if @validators
|
68
|
+
options[:validators].each do |key, value|
|
69
|
+
if @validators.key?(key)
|
70
|
+
@validators[key].merge! value
|
71
|
+
else
|
72
|
+
@validators[key] = value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def insert_validators_into_script(script)
|
79
|
+
# There is probably a more performant way of doing this
|
80
|
+
# But using String#sub has some issues. Undocumented "features"
|
81
|
+
if script
|
82
|
+
script = script.split(/"validator_hash"/)
|
83
|
+
script = "#{script[0]}#{construct_validators.to_json}#{script[1]}"
|
84
|
+
end
|
85
|
+
|
86
|
+
script
|
87
|
+
end
|
88
|
+
|
89
|
+
def construct_validators
|
90
|
+
@validators.inject({}) do |validator_hash, object_opts|
|
91
|
+
option_hash = object_opts[1].inject({}) do |option_hash, attr|
|
92
|
+
option_hash.merge!(attr[0] => attr[1][:options])
|
93
|
+
end
|
94
|
+
|
95
|
+
if object_opts[0].respond_to?(:client_side_validation_hash)
|
96
|
+
validation_hash = object_opts[0].client_side_validation_hash(option_hash)
|
97
|
+
else
|
98
|
+
validation_hash = {}
|
99
|
+
end
|
100
|
+
|
101
|
+
option_hash.each_key do |attr|
|
102
|
+
if validation_hash[attr]
|
103
|
+
validator_hash.merge!(object_opts[1][attr][:name] => validation_hash[attr])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
validator_hash
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def client_side_form_settings(object, options, builder)
|
112
|
+
if options[:validate]
|
113
|
+
if options[:id]
|
114
|
+
var_name = options[:id]
|
115
|
+
else
|
116
|
+
var_name = if object.respond_to?(:persisted?) && object.persisted?
|
117
|
+
options[:as] ? "edit_#{options[:as]}" : [options[:namespace], dom_id(object, :edit)].compact.join("_")
|
118
|
+
else
|
119
|
+
options[:as] ? "new_#{options[:as]}" : [options[:namespace], dom_id(object)].compact.join("_")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
if Rails4ClientSideValidations::Config.number_format_with_locale and defined?(I18n)
|
124
|
+
number_format = I18n.t("number.format").slice(:separator, :delimiter)
|
125
|
+
else
|
126
|
+
number_format = {:separator=>".", :delimiter=>","}
|
127
|
+
end
|
128
|
+
patterns = {:numericality=>"/^(-|\\+)?(?:\\d+|\\d{1,3}(?:\\#{number_format[:delimiter]}\\d{3})+)(?:\\#{number_format[:separator]}\\d*)?$/"}
|
129
|
+
|
130
|
+
|
131
|
+
content_tag(:script) do
|
132
|
+
"//<![CDATA[\nif(window.Rails4ClientSideValidations===undefined)window.Rails4ClientSideValidations={};window.Rails4ClientSideValidations.disabled_validators=#{Rails4ClientSideValidations::Config.disabled_validators.to_json};window.Rails4ClientSideValidations.number_format=#{number_format.to_json};if(window.Rails4ClientSideValidations.patterns===undefined)window.Rails4ClientSideValidations.patterns = {};window.Rails4ClientSideValidations.patterns.numericality=#{patterns[:numericality]};if(window.Rails4ClientSideValidations.remote_validators_prefix===undefined)window.Rails4ClientSideValidations.remote_validators_prefix='#{(Rails4ClientSideValidations::Config.root_path||"").sub(/\/+\Z/,'')}';if(window.Rails4ClientSideValidations.forms===undefined)window.Rails4ClientSideValidations.forms={};window.Rails4ClientSideValidations.forms['#{var_name}'] = #{builder.client_side_form_settings(options, self).merge(:validators => 'validator_hash').to_json};\n//]]>".html_safe
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Rails4ClientSideValidations::ActionView::Helpers
|
2
|
+
module FormTagHelper
|
3
|
+
private
|
4
|
+
def html_options_for_form(url_for_options, options, *parameters_for_url)
|
5
|
+
options.stringify_keys!
|
6
|
+
html_options = {}
|
7
|
+
html_options['data-validate'] = options.delete('validate') if options['validate']
|
8
|
+
html_options.merge!(super(url_for_options, options, *parameters_for_url))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'rails4_client_side_validations/core_ext'
|
2
|
+
|
3
|
+
module Rails4ClientSideValidations::ActiveModel
|
4
|
+
module Validator
|
5
|
+
|
6
|
+
def client_side_hash(model, attribute, force = nil)
|
7
|
+
build_client_side_hash(model, attribute, self.options.dup)
|
8
|
+
end
|
9
|
+
|
10
|
+
def copy_conditional_attributes(to, from)
|
11
|
+
[:if, :unless].each { |key| to[key] = from[key] if from[key].present? }
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def build_client_side_hash(model, attribute, options)
|
17
|
+
{ :message => model.errors.generate_message(attribute, message_type, options) }.merge(options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :if, :unless]))
|
18
|
+
end
|
19
|
+
|
20
|
+
def message_type
|
21
|
+
kind
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Validations
|
26
|
+
def client_side_validation_hash(force = nil)
|
27
|
+
_validators.inject({}) do |attr_hash, attr|
|
28
|
+
unless [nil, :block].include?(attr[0])
|
29
|
+
|
30
|
+
validator_hash = attr[1].inject(Hash.new { |h,k| h[k] = []}) do |kind_hash, validator|
|
31
|
+
if can_use_for_client_side_validation?(attr[0], validator, force)
|
32
|
+
if client_side_hash = validator.client_side_hash(self, attr[0], extract_force_option(attr[0], force))
|
33
|
+
kind_hash[validator.kind] << client_side_hash.except(:on, :if, :unless)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
kind_hash
|
38
|
+
end
|
39
|
+
|
40
|
+
if validator_hash.present?
|
41
|
+
attr_hash.merge!(attr[0] => validator_hash)
|
42
|
+
else
|
43
|
+
attr_hash
|
44
|
+
end
|
45
|
+
else
|
46
|
+
attr_hash
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def extract_force_option(attr, force)
|
54
|
+
case force
|
55
|
+
when FalseClass, TrueClass, NilClass
|
56
|
+
force
|
57
|
+
when Hash
|
58
|
+
extract_force_option(nil, force[attr])
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def can_use_for_client_side_validation?(attr, validator, force)
|
65
|
+
if validator_turned_off?(attr, validator, force)
|
66
|
+
result = false
|
67
|
+
else
|
68
|
+
# Yeah yeah, #new_record? is not part of ActiveModel :p
|
69
|
+
result = ((self.respond_to?(:new_record?) && validator.options[:on] == (self.new_record? ? :create : :update)) || validator.options[:on].nil?)
|
70
|
+
result = result && validator.kind != :block
|
71
|
+
|
72
|
+
if validator.options[:if] || validator.options[:unless]
|
73
|
+
if validator.options[:if] && validator.options[:if] =~ /changed\?/
|
74
|
+
result = true
|
75
|
+
else result = can_force_validator?(attr, validator, force)
|
76
|
+
if validator.options[:if]
|
77
|
+
result = result && run_conditional(validator.options[:if])
|
78
|
+
end
|
79
|
+
if validator.options[:unless]
|
80
|
+
result = result && !run_conditional(validator.options[:unless])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
result
|
87
|
+
end
|
88
|
+
|
89
|
+
def run_conditional(method_name_value_or_proc)
|
90
|
+
if method_name_value_or_proc.respond_to?(:call)
|
91
|
+
method_name_value_or_proc.call(self)
|
92
|
+
else
|
93
|
+
self.send(method_name_value_or_proc)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def validator_turned_off?(attr, validator, force)
|
98
|
+
case force
|
99
|
+
when FalseClass
|
100
|
+
true
|
101
|
+
when Hash
|
102
|
+
case force[attr]
|
103
|
+
when FalseClass
|
104
|
+
true
|
105
|
+
when Hash
|
106
|
+
force[attr][validator.kind] == false
|
107
|
+
else
|
108
|
+
false
|
109
|
+
end
|
110
|
+
else
|
111
|
+
::Rails4ClientSideValidations::Config.disabled_validators.include?(validator.kind)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def can_force_validator?(attr, validator, force)
|
116
|
+
case force
|
117
|
+
when TrueClass
|
118
|
+
true
|
119
|
+
when Hash
|
120
|
+
case force[attr]
|
121
|
+
when TrueClass
|
122
|
+
true
|
123
|
+
when Hash
|
124
|
+
force[attr][validator.kind]
|
125
|
+
else
|
126
|
+
false
|
127
|
+
end
|
128
|
+
else
|
129
|
+
false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
ActiveModel::Validator.send(:include, Rails4ClientSideValidations::ActiveModel::Validator)
|
136
|
+
ActiveModel::Validations.send(:include, Rails4ClientSideValidations::ActiveModel::Validations)
|
137
|
+
|
138
|
+
%w{absence acceptance exclusion inclusion length format numericality presence}.each do |validator|
|
139
|
+
require "rails4_client_side_validations/active_model/#{validator}"
|
140
|
+
validator.capitalize!
|
141
|
+
eval "ActiveModel::Validations::#{validator}Validator.send(:include, Rails4ClientSideValidations::ActiveModel::#{validator})"
|
142
|
+
end
|
143
|
+
|