pcai_client_side_validations 3.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/client_side_validations.gemspec +42 -0
  2. data/lib/client_side_validations.rb +13 -0
  3. data/lib/client_side_validations/action_view.rb +14 -0
  4. data/lib/client_side_validations/action_view/form_builder.rb +157 -0
  5. data/lib/client_side_validations/action_view/form_helper.rb +86 -0
  6. data/lib/client_side_validations/action_view/form_tag_helper.rb +12 -0
  7. data/lib/client_side_validations/active_model.rb +60 -0
  8. data/lib/client_side_validations/active_model/acceptance.rb +10 -0
  9. data/lib/client_side_validations/active_model/exclusion.rb +15 -0
  10. data/lib/client_side_validations/active_model/format.rb +10 -0
  11. data/lib/client_side_validations/active_model/inclusion.rb +15 -0
  12. data/lib/client_side_validations/active_model/length.rb +24 -0
  13. data/lib/client_side_validations/active_model/numericality.rb +31 -0
  14. data/lib/client_side_validations/active_model/presence.rb +10 -0
  15. data/lib/client_side_validations/active_record.rb +11 -0
  16. data/lib/client_side_validations/active_record/middleware.rb +33 -0
  17. data/lib/client_side_validations/active_record/uniqueness.rb +28 -0
  18. data/lib/client_side_validations/core_ext.rb +3 -0
  19. data/lib/client_side_validations/core_ext/range.rb +10 -0
  20. data/lib/client_side_validations/core_ext/regexp.rb +14 -0
  21. data/lib/client_side_validations/engine.rb +6 -0
  22. data/lib/client_side_validations/files.rb +8 -0
  23. data/lib/client_side_validations/formtastic.rb +21 -0
  24. data/lib/client_side_validations/middleware.rb +81 -0
  25. data/lib/client_side_validations/mongo_mapper.rb +9 -0
  26. data/lib/client_side_validations/mongo_mapper/middleware.rb +20 -0
  27. data/lib/client_side_validations/mongo_mapper/uniqueness.rb +28 -0
  28. data/lib/client_side_validations/mongoid.rb +9 -0
  29. data/lib/client_side_validations/mongoid/middleware.rb +20 -0
  30. data/lib/client_side_validations/mongoid/uniqueness.rb +28 -0
  31. data/lib/client_side_validations/simple_form.rb +24 -0
  32. data/lib/client_side_validations/version.rb +3 -0
  33. data/lib/generators/client_side_validations/copy_asset_generator.rb +36 -0
  34. data/lib/generators/client_side_validations/install_generator.rb +45 -0
  35. data/lib/generators/templates/client_side_validations/README.rails.3.0 +6 -0
  36. data/lib/generators/templates/client_side_validations/README.rails.3.1 +7 -0
  37. data/lib/generators/templates/client_side_validations/initializer.rb +14 -0
  38. data/vendor/assets/javascripts/rails.validations.js +410 -0
  39. metadata +226 -0
@@ -0,0 +1,24 @@
1
+ module ClientSideValidations::ActiveModel
2
+ module Length
3
+
4
+ def client_side_hash(model, attribute)
5
+ options = self.options.dup
6
+ hash = { :messages => {} }
7
+ hash[:js_tokenizer] = options[:js_tokenizer] if options[:js_tokenizer]
8
+ hash[:allow_blank] = true if options[:allow_blank]
9
+
10
+ self.class::MESSAGES.each do |option, message_type|
11
+ if count = options[option]
12
+ options[:message] = options[message_type]
13
+ options.delete(:message) if options[:message].nil?
14
+ hash[:messages][option] = model.errors.generate_message(attribute, message_type, options.merge(:count => count))
15
+ hash[option] = count
16
+ end
17
+ end
18
+
19
+ hash
20
+ end
21
+
22
+ end
23
+ end
24
+
@@ -0,0 +1,31 @@
1
+ module ClientSideValidations::ActiveModel
2
+ module Numericality
3
+
4
+ OPTION_MAP = {}
5
+
6
+ def self.included(base)
7
+ OPTION_MAP.merge!(base::CHECKS.keys.inject({}) { |hash, key| hash.merge!(key => key) })
8
+ end
9
+
10
+ def client_side_hash(model, attribute)
11
+ options = self.options.dup
12
+ hash = { :messages => { :numericality => model.errors.generate_message(attribute, :not_a_number, options) } }
13
+
14
+ if options[:only_integer]
15
+ hash[:messages][:only_integer] = model.errors.generate_message(attribute, :not_an_integer, options)
16
+ hash[:only_integer] = true
17
+ end
18
+
19
+ OPTION_MAP.each do |option, message_type|
20
+ if count = options[option]
21
+ hash[:messages][option] = model.errors.generate_message(attribute, message_type, options.merge(:count => count))
22
+ hash[option] = count
23
+ end
24
+ end
25
+
26
+ hash
27
+ end
28
+
29
+ end
30
+ end
31
+
@@ -0,0 +1,10 @@
1
+ module ClientSideValidations::ActiveModel
2
+ module Presence
3
+ private
4
+
5
+ def message_type
6
+ :blank
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,11 @@
1
+ require 'client_side_validations/active_model'
2
+ require 'client_side_validations/active_record/middleware'
3
+
4
+ %w{uniqueness}.each do |validator|
5
+ require "client_side_validations/active_record/#{validator}"
6
+ validator.capitalize!
7
+ eval "ActiveRecord::Validations::#{validator}Validator.send(:include, ClientSideValidations::ActiveRecord::#{validator})"
8
+ end
9
+
10
+ ActiveRecord::Base.send(:include, ClientSideValidations::ActiveModel::Validations)
11
+
@@ -0,0 +1,33 @@
1
+ module ClientSideValidations::ActiveRecord
2
+ class Middleware
3
+
4
+ def self.is_unique?(klass, attribute, value, params)
5
+ column = klass.columns_hash[attribute.to_s]
6
+ value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s if column.text?
7
+
8
+ t = klass.arel_table
9
+
10
+ if params[:case_sensitive] == 'true'
11
+ if t.engine.connection.instance_variable_get("@config")[:adapter] == 'mysql'
12
+ relation = Arel::Nodes::SqlLiteral.new("BINARY #{t[attribute].eq(value).to_sql}")
13
+ else
14
+ relation = t[attribute].eq(value)
15
+ end
16
+ else
17
+ relation = t[attribute].matches(value)
18
+ end
19
+
20
+ if relation.is_a?(Arel::Nodes::SqlLiteral)
21
+ relation = Arel::Nodes::SqlLiteral.new("BINARY #{t[attribute].eq(value).to_sql} AND #{t.primary_key.not_eq(params[:id]).to_sql}")
22
+ else
23
+ relation = relation.and(t.primary_key.not_eq(params[:id])) if params[:id]
24
+ end
25
+
26
+ (params[:scope] || {}).each do |key, value|
27
+ relation = relation.and(t[key].eq(value))
28
+ end
29
+
30
+ !klass.where(relation).exists?
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ module ClientSideValidations::ActiveRecord
2
+ module Uniqueness
3
+ def client_side_hash(model, attribute)
4
+ hash = {}
5
+ hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
6
+ hash[:case_sensitive] = options[:case_sensitive]
7
+ hash[:id] = model.id unless model.new_record?
8
+ if options.key?(:scope) && options[:scope].present?
9
+ hash[:scope] = Array.wrap(options[:scope]).inject({}) do |scope_hash, scope_item|
10
+ scope_hash.merge!(scope_item => model.send(scope_item))
11
+ end
12
+ end
13
+
14
+ unless model.class.name.demodulize == model.class.name
15
+ hash[:class] = model.class.name.underscore
16
+ end
17
+
18
+ hash
19
+ end
20
+
21
+ private
22
+
23
+ def message_type
24
+ :taken
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,3 @@
1
+ require 'active_support/json'
2
+ require 'client_side_validations/core_ext/range'
3
+ require 'client_side_validations/core_ext/regexp'
@@ -0,0 +1,10 @@
1
+ class Range
2
+ def as_json(options = nil)
3
+ [first, last]
4
+ end
5
+
6
+ def to_json(options = nil)
7
+ as_json(options).inspect
8
+ end
9
+ end
10
+
@@ -0,0 +1,14 @@
1
+ class Regexp
2
+ def as_json(options = nil)
3
+ Regexp.new inspect.sub("\\A","^").sub("\\Z","$").sub("\\z","$").sub(/^\//,"").sub(/\/[a-z]*$/,""), self.options
4
+ end
5
+
6
+ def to_json(options = nil)
7
+ as_json(options).inspect
8
+ end
9
+
10
+ def encode_json(encoder)
11
+ inspect
12
+ end
13
+ end
14
+
@@ -0,0 +1,6 @@
1
+ module ClientSideValidations
2
+ class Engine < ::Rails::Engine
3
+ config.app_middleware.use ClientSideValidations::Middleware::Validators
4
+ end
5
+ end
6
+
@@ -0,0 +1,8 @@
1
+ # This is only used by dependant libraries that need to find the files
2
+
3
+ module ClientSideValidations
4
+ module Files
5
+ Initializer = File.expand_path(File.dirname(__FILE__) + '/../generators/templates/client_side_validations/initializer.rb')
6
+ Javascript = File.expand_path(File.dirname(__FILE__) + '/../../vendor/assets/javascripts/rails.validations.js')
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ module ClientSideValidations
2
+ module Formtastic
3
+ module FormBuilder
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ def self.client_side_form_settings(options, form_helper)
8
+ {
9
+ :type => self.to_s,
10
+ :inline_error_class => ::Formtastic::FormBuilder.default_inline_error_class
11
+ }
12
+ end
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+
20
+ Formtastic::FormBuilder.send(:include, ClientSideValidations::Formtastic::FormBuilder)
21
+
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+
3
+ require 'client_side_validations/core_ext'
4
+
5
+ module ClientSideValidations
6
+
7
+ module Middleware
8
+ class Validators
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def call(env)
14
+ case env['PATH_INFO']
15
+ when %r{\/validators\/(\w+)}
16
+ "::ClientSideValidations::Middleware::#{$1.camelize}".constantize.new(env).response
17
+ else
18
+ @app.call(env)
19
+ end
20
+ end
21
+ end
22
+
23
+ class Base
24
+ attr_accessor :request, :body, :status
25
+
26
+ def initialize(env)
27
+ self.body = ''
28
+ self.status = 200
29
+ self.request = ActionDispatch::Request.new(env)
30
+ end
31
+
32
+ def response
33
+ [status, {'Content-Type' => content_type, 'Content-Length' => body.length.to_s}, [body]]
34
+ end
35
+
36
+ def content_type
37
+ 'application/json'
38
+ end
39
+ end
40
+
41
+ class Uniqueness < Base
42
+ IGNORE_PARAMS = %w{case_sensitive id scope}
43
+
44
+ def response
45
+ if is_unique?
46
+ self.status = 404
47
+ self.body = 'true'
48
+ else
49
+ self.status = 200
50
+ self.body = 'false'
51
+ end
52
+ super
53
+ end
54
+
55
+ private
56
+
57
+ def is_unique?
58
+ resource = extract_resource
59
+ klass = resource.classify.constantize
60
+ attribute = request.params[resource].keys.first
61
+ value = request.params[resource][attribute]
62
+
63
+ if (defined?(::ActiveRecord::Base) && klass < ::ActiveRecord::Base)
64
+ middleware_klass = ClientSideValidations::ActiveRecord::Middleware
65
+ elsif (defined?(::Mongoid::Document) && klass.included_modules.include?(::Mongoid::Document))
66
+ middleware_klass = ClientSideValidations::Mongoid::Middleware
67
+ elsif (defined?(::MongoMapper::Document) && klass.included_modules.include?(::MongoMapper::Document))
68
+ middleware_klass = ClientSideValidations::MongoMapper::Middleware
69
+ end
70
+
71
+ middleware_klass.is_unique?(klass, attribute, value, request.params)
72
+ end
73
+
74
+ def extract_resource
75
+ parent_key = (request.params.keys - IGNORE_PARAMS).first
76
+ end
77
+ end
78
+ end
79
+
80
+ end
81
+
@@ -0,0 +1,9 @@
1
+ require 'client_side_validations/active_model'
2
+ require 'client_side_validations/mongo_mapper/middleware'
3
+
4
+ %w{uniqueness}.each do |validator|
5
+ require "client_side_validations/mongo_mapper/#{validator}"
6
+ validator.capitalize!
7
+ eval "MongoMapper::Plugins::Validations::#{validator}Validator.send(:include, ClientSideValidations::MongoMapper::#{validator})"
8
+ end
9
+
@@ -0,0 +1,20 @@
1
+ module ClientSideValidations::MongoMapper
2
+ class Middleware
3
+
4
+ # Still need to handle embedded documents
5
+ def self.is_unique?(klass, attribute, value, params)
6
+ if params[:case_sensitive] == 'false'
7
+ value = Regexp.new("^#{Regexp.escape(value.to_s)}$", Regexp::IGNORECASE)
8
+ end
9
+
10
+ criteria = klass.where(attribute => value)
11
+ criteria = criteria.where(:_id => {'$ne' => BSON::ObjectId(params[:id])}) if params[:id]
12
+
13
+ (params[:scope] || {}).each do |key, value|
14
+ criteria = criteria.where(key => value)
15
+ end
16
+
17
+ !criteria.exists?
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ module ClientSideValidations::MongoMapper
2
+ module Uniqueness
3
+ def client_side_hash(model, attribute)
4
+ hash = {}
5
+ hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
6
+ hash[:case_sensitive] = options[:case_sensitive] if options.key?(:case_sensitive)
7
+ hash[:id] = model.id unless model.new_record?
8
+ if options.key?(:scope) && options[:scope].present?
9
+ hash[:scope] = Array.wrap(options[:scope]).inject({}) do |scope_hash, scope_item|
10
+ scope_hash.merge!(scope_item => model.send(scope_item))
11
+ end
12
+ end
13
+
14
+ unless model.class.name.demodulize == model.class.name
15
+ hash[:class] = model.class.name.underscore
16
+ end
17
+
18
+ hash
19
+ end
20
+
21
+ private
22
+
23
+ def message_type
24
+ :taken
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,9 @@
1
+ require 'client_side_validations/active_model'
2
+ require 'client_side_validations/mongoid/middleware'
3
+
4
+ %w{uniqueness}.each do |validator|
5
+ require "client_side_validations/mongoid/#{validator}"
6
+ validator.capitalize!
7
+ eval "Mongoid::Validations::#{validator}Validator.send(:include, ClientSideValidations::Mongoid::#{validator})"
8
+ end
9
+
@@ -0,0 +1,20 @@
1
+ module ClientSideValidations::Mongoid
2
+ class Middleware
3
+
4
+ # Still need to handle embedded documents
5
+ def self.is_unique?(klass, attribute, value, params)
6
+ if params[:case_sensitive] == 'false'
7
+ value = Regexp.new("^#{Regexp.escape(value.to_s)}$", Regexp::IGNORECASE)
8
+ end
9
+
10
+ criteria = klass.where(attribute => value)
11
+ criteria = criteria.where(:_id => {'$ne' => BSON::ObjectId(params[:id])}) if params[:id]
12
+
13
+ (params[:scope] || {}).each do |key, value|
14
+ criteria = criteria.where(key => value)
15
+ end
16
+
17
+ !criteria.exists?
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ module ClientSideValidations::Mongoid
2
+ module Uniqueness
3
+ def client_side_hash(model, attribute)
4
+ hash = {}
5
+ hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
6
+ hash[:case_sensitive] = options[:case_sensitive] if options.key?(:case_sensitive)
7
+ hash[:id] = model.id unless model.new_record?
8
+ if options.key?(:scope) && options[:scope].present?
9
+ hash[:scope] = Array.wrap(options[:scope]).inject({}) do |scope_hash, scope_item|
10
+ scope_hash.merge!(scope_item => model.send(scope_item))
11
+ end
12
+ end
13
+
14
+ unless model.class.name.demodulize == model.class.name
15
+ hash[:class] = model.class.name.underscore
16
+ end
17
+
18
+ hash
19
+ end
20
+
21
+ private
22
+
23
+ def message_type
24
+ :taken
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,24 @@
1
+ module ClientSideValidations
2
+ module SimpleForm
3
+ module FormBuilder
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ def self.client_side_form_settings(options, form_helper)
8
+ {
9
+ :type => self.to_s,
10
+ :error_class => ::SimpleForm.error_class,
11
+ :error_tag => ::SimpleForm.error_tag,
12
+ :wrapper_error_class => ::SimpleForm.wrapper_error_class,
13
+ :wrapper_tag => ::SimpleForm.wrapper_tag
14
+ }
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
22
+
23
+ SimpleForm::FormBuilder.send(:include, ClientSideValidations::SimpleForm::FormBuilder)
24
+