client_side_validations 3.0.4 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/client_side_validations.gemspec +4 -7
  2. data/lib/client_side_validations/action_view/form_builder.rb +56 -6
  3. data/lib/client_side_validations/action_view/form_helper.rb +21 -3
  4. data/lib/client_side_validations/action_view.rb +4 -3
  5. data/lib/client_side_validations/active_model/length.rb +12 -10
  6. data/lib/client_side_validations/active_model/numericality.rb +14 -9
  7. data/lib/client_side_validations/active_model.rb +21 -13
  8. data/lib/client_side_validations/active_record/middleware.rb +5 -1
  9. data/lib/client_side_validations/active_record/uniqueness.rb +10 -8
  10. data/lib/client_side_validations/engine.rb +6 -0
  11. data/lib/client_side_validations/files.rb +8 -0
  12. data/lib/client_side_validations/formtastic.rb +3 -3
  13. data/lib/client_side_validations/middleware.rb +5 -7
  14. data/lib/client_side_validations/mongo_mapper/middleware.rb +20 -0
  15. data/lib/client_side_validations/mongo_mapper/uniqueness.rb +28 -0
  16. data/lib/client_side_validations/mongo_mapper.rb +9 -0
  17. data/lib/client_side_validations/mongoid/uniqueness.rb +10 -8
  18. data/lib/client_side_validations/version.rb +1 -1
  19. data/lib/client_side_validations.rb +8 -3
  20. data/lib/generators/client_side_validations/copy_asset_generator.rb +23 -0
  21. data/lib/generators/client_side_validations/install_generator.rb +18 -6
  22. data/lib/generators/templates/client_side_validations/README.rails.3.0 +6 -0
  23. data/lib/generators/templates/client_side_validations/README.rails.3.1 +7 -0
  24. data/lib/generators/templates/{client_side_validations.rb → client_side_validations/initializer.rb} +1 -1
  25. data/test/action_view/cases/helper.rb +34 -12
  26. data/test/action_view/cases/test_helpers.rb +264 -1
  27. data/test/action_view/cases/test_legacy_helpers.rb +12 -1
  28. data/test/active_model/cases/test_validations.rb +21 -8
  29. data/test/active_record/cases/test_middleware.rb +41 -16
  30. data/test/active_record/cases/test_uniqueness_validator.rb +5 -0
  31. data/test/active_record/models/user.rb +4 -0
  32. data/test/base_helper.rb +2 -0
  33. data/test/core_ext/cases/test_core_ext.rb +1 -0
  34. data/test/formtastic/cases/helper.rb +5 -0
  35. data/test/formtastic/cases/test_form_builder.rb +3 -3
  36. data/test/formtastic/cases/test_form_helper.rb +3 -4
  37. data/test/generators/cases/test_generators.rb +31 -0
  38. data/test/javascript/public/test/callbacks/elementAfter.js +1 -1
  39. data/test/javascript/public/test/callbacks/elementBefore.js +1 -1
  40. data/test/javascript/public/test/callbacks/elementFail.js +1 -1
  41. data/test/javascript/public/test/callbacks/elementPass.js +1 -1
  42. data/test/javascript/public/test/callbacks/formAfter.js +1 -1
  43. data/test/javascript/public/test/callbacks/formBefore.js +1 -1
  44. data/test/javascript/public/test/callbacks/formFail.js +1 -1
  45. data/test/javascript/public/test/callbacks/formPass.js +1 -1
  46. data/test/javascript/public/test/form_builders/validateForm.js +1 -1
  47. data/test/javascript/public/test/form_builders/validateFormtastic.js +2 -2
  48. data/test/javascript/public/test/form_builders/validateNestedForm.js +66 -0
  49. data/test/javascript/public/test/form_builders/validateSimpleForm.js +1 -1
  50. data/test/javascript/public/test/validateElement.js +36 -1
  51. data/test/javascript/public/test/validators/length.js +7 -1
  52. data/test/javascript/public/test/validators/numericality.js +7 -0
  53. data/test/javascript/public/test/validators/presence.js +6 -0
  54. data/test/javascript/public/test/validators/uniqueness.js +8 -1
  55. data/test/javascript/server.rb +9 -3
  56. data/test/javascript/views/index.erb +1 -1
  57. data/test/javascript/views/layout.erb +1 -1
  58. data/test/middleware/cases/helper.rb +3 -0
  59. data/test/mongo_mapper/cases/helper.rb +9 -0
  60. data/test/mongo_mapper/cases/test_base.rb +15 -0
  61. data/test/mongo_mapper/cases/test_middleware.rb +77 -0
  62. data/test/mongo_mapper/cases/test_uniqueness_validator.rb +50 -0
  63. data/test/mongo_mapper/models/magazine.rb +11 -0
  64. data/test/mongoid/cases/test_middleware.rb +15 -6
  65. data/test/mongoid/cases/test_uniqueness_validator.rb +5 -0
  66. data/test/mongoid/models/book.rb +4 -0
  67. data/test/simple_form/cases/helper.rb +3 -0
  68. data/test/simple_form/cases/test_form_helper.rb +3 -1
  69. data/test/test_loader.rb +6 -0
  70. data/{javascript → vendor/assets/javascripts}/rails.validations.js +31 -17
  71. metadata +44 -23
  72. data/lib/generators/templates/README +0 -7
  73. data/test/generators/cases/test_install_generator.rb +0 -15
@@ -1,8 +1,14 @@
1
1
  require 'base_helper'
2
2
  require 'action_view'
3
- require 'client_side_validations/action_view'
4
- require 'action_view/template/handlers/erb'
3
+ require 'action_view/template'
5
4
  require 'action_view/models'
5
+ require 'client_side_validations/action_view'
6
+
7
+ module ActionController
8
+ class Base
9
+ include ActionDispatch::Routing::RouteSet.new.url_helpers
10
+ end
11
+ end
6
12
 
7
13
  module ActionViewTestSetup
8
14
  include ::ClientSideValidations::ActionView::Helpers::FormHelper
@@ -12,6 +18,19 @@ module ActionViewTestSetup
12
18
  @output_buffer = super
13
19
  end
14
20
 
21
+ Routes = ActionDispatch::Routing::RouteSet.new
22
+ Routes.draw do
23
+ resources :posts do
24
+ resources :comments
25
+ end
26
+ end
27
+
28
+ def _routes
29
+ Routes
30
+ end
31
+
32
+ include Routes.url_helpers
33
+
15
34
  def setup
16
35
  super
17
36
 
@@ -67,14 +86,11 @@ module ActionViewTestSetup
67
86
  @post.body = "Back to the hill and over it again!"
68
87
  @post.secret = 1
69
88
  @post.written_on = Date.new(2004, 6, 15)
70
- end
71
89
 
72
- def url_for(object)
73
- @url_for_options = object
74
- if object.is_a?(Hash)
75
- "http://www.example.com"
90
+ if defined?(ActionView::OutputFlow)
91
+ @view_flow = ActionView::OutputFlow.new
76
92
  else
77
- super
93
+ @_content_for = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
78
94
  end
79
95
  end
80
96
 
@@ -85,11 +101,12 @@ module ActionViewTestSetup
85
101
  txt << %{</div>}
86
102
  end
87
103
 
88
- def form_text(action = "http://www.example.com", id = nil, html_class = nil, remote = nil, validators = nil)
104
+ def form_text(action = "http://www.example.com", id = nil, html_class = nil, remote = nil, validators = nil, file = nil)
89
105
  txt = %{<form accept-charset="UTF-8" action="#{action}"}
90
106
  txt << %{ data-remote="true"} if remote
91
107
  txt << %{ class="#{html_class}"} if html_class
92
108
  txt << %{ data-validate="true"} if validators
109
+ txt << %{ enctype="multipart/form-data"} if file
93
110
  txt << %{ id="#{id}"} if id
94
111
  txt << %{ method="post"}
95
112
  txt << %{ novalidate="novalidate"} if validators
@@ -100,20 +117,24 @@ module ActionViewTestSetup
100
117
  contents = block_given? ? yield : ""
101
118
 
102
119
  if options.is_a?(Hash)
103
- method, remote, validators = options.values_at(:method, :remote, :validators)
120
+ method, remote, validators, file = options.values_at(:method, :remote, :validators, :file)
104
121
  else
105
122
  method = options
106
123
  end
107
124
 
108
- html = form_text(action, id, html_class, remote, validators) + snowman(method) + (contents || "") + "</form>"
125
+ html = form_text(action, id, html_class, remote, validators, file) + snowman(method) + (contents || "") + "</form>"
109
126
 
110
127
  if options.is_a?(Hash) && options[:validators]
111
- html + %Q{<script>var #{id} = #{client_side_form_settings_helper.merge(:validators => validators).to_json};</script>}
128
+ build_script_tag(html, id, options[:validators])
112
129
  else
113
130
  html
114
131
  end
115
132
  end
116
133
 
134
+ def build_script_tag(html, id, validators)
135
+ (html || "") + %Q{<script>window['#{id}'] = #{client_side_form_settings_helper.merge(:validators => validators).to_json};</script>}
136
+ end
137
+
117
138
  protected
118
139
  def comments_path(post)
119
140
  "/posts/#{post.id}/comments"
@@ -152,3 +173,4 @@ module ActionViewTestSetup
152
173
  end
153
174
 
154
175
  end
176
+
@@ -44,7 +44,7 @@ class ClientSideValidations::ActionViewHelpersTest < ActionView::TestCase
44
44
  end
45
45
 
46
46
  validators = {'post[cost]' => {:presence => {:message => "can't be blank"}}}
47
- expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
47
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators, :file => true) do
48
48
  %{<input data-validate="true" id="post_cost" name="post[cost]" type="file" />}
49
49
  end
50
50
  assert_equal expected, output_buffer
@@ -296,6 +296,18 @@ class ClientSideValidations::ActionViewHelpersTest < ActionView::TestCase
296
296
  assert_equal expected, output_buffer
297
297
  end
298
298
 
299
+ def test_select_multiple
300
+ form_for(@post, :validate => true) do |f|
301
+ concat f.select(:cost, [], {}, :multiple => true)
302
+ end
303
+
304
+ validators = {'post[cost][]' => {:presence => {:message => "can't be blank"}}}
305
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
306
+ %{<select data-validate="true" id="post_cost" multiple="multiple" name="post[cost][]"></select>}
307
+ end
308
+ assert_equal expected, output_buffer
309
+ end
310
+
299
311
  def test_collection_select
300
312
  form_for(@post, :validate => true) do |f|
301
313
  concat f.collection_select(:cost, [], :id, :name)
@@ -333,5 +345,256 @@ class ClientSideValidations::ActionViewHelpersTest < ActionView::TestCase
333
345
  end
334
346
  assert_equal expected, output_buffer
335
347
  end
348
+
349
+ def test_conditional_validator_filters
350
+ hash = {
351
+ :cost => {
352
+ :presence => {
353
+ :message => "can't be blank",
354
+ :unless => :cannot_validate?
355
+ }
356
+ },
357
+ :title => {
358
+ :presence => {
359
+ :message => "can't be blank",
360
+ :if => :can_validate?
361
+ }
362
+ }
363
+ }
364
+
365
+ @post.title = nil
366
+ @post.stubs(:cannot_validate?).returns(false)
367
+ @post.stubs(:can_validate?).returns(true)
368
+ @post.stubs(:client_side_validation_hash).returns(hash)
369
+ form_for(@post, :validate => true) do |f|
370
+ concat f.text_field(:cost)
371
+ concat f.text_field(:title)
372
+ end
373
+
374
+ validators = {}
375
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
376
+ %{<input id="post_cost" name="post[cost]" size="30" type="text" />} +
377
+ %{<input id="post_title" name="post[title]" size="30" type="text" />}
378
+ end
379
+ assert_equal expected, output_buffer
380
+ end
381
+
382
+ def test_conditional_validators_should_be_filtered
383
+ hash = {
384
+ :cost => {
385
+ :presence => {
386
+ :message => "can't be blank",
387
+ :unless => :cannot_validate?
388
+ }
389
+ },
390
+ :title => {
391
+ :presence => {
392
+ :message => "can't be blank",
393
+ :if => :can_validate?
394
+ }
395
+ }
396
+ }
397
+
398
+ @post.title = nil
399
+ @post.stubs(:cannot_validate?).returns(false)
400
+ @post.stubs(:can_validate?).returns(true)
401
+ @post.stubs(:client_side_validation_hash).returns(hash)
402
+ form_for(@post, :validate => true) do |f|
403
+ concat f.text_field(:cost)
404
+ concat f.text_field(:title)
405
+ end
406
+
407
+ validators = {}
408
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
409
+ %{<input id="post_cost" name="post[cost]" size="30" type="text" />} +
410
+ %{<input id="post_title" name="post[title]" size="30" type="text" />}
411
+ end
412
+ assert_equal expected, output_buffer
413
+ end
414
+
415
+ def test_conditional_validator_filters_being_forced
416
+ hash = {
417
+ :cost => {
418
+ :presence => {
419
+ :message => "can't be blank",
420
+ :unless => :cannot_validate?
421
+ }
422
+ },
423
+ :title => {
424
+ :presence => {
425
+ :message => "can't be blank",
426
+ :if => :can_validate?
427
+ }
428
+ }
429
+ }
430
+
431
+ @post.title = nil
432
+ @post.stubs(:cannot_validate?).returns(false)
433
+ @post.stubs(:can_validate?).returns(true)
434
+ @post.stubs(:client_side_validation_hash).returns(hash)
435
+ form_for(@post, :validate => true) do |f|
436
+ concat f.text_field(:cost, :validate => true)
437
+ concat f.text_field(:title, :validate => true)
438
+ end
439
+
440
+ validators = {
441
+ 'post[cost]' => {:presence => {:message => "can't be blank"}},
442
+ 'post[title]' => {:presence => {:message => "can't be blank"}}
443
+ }
444
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
445
+ %{<input data-validate="true" id="post_cost" name="post[cost]" size="30" type="text" />} +
446
+ %{<input data-validate="true" id="post_title" name="post[title]" size="30" type="text" />}
447
+ end
448
+ assert_equal expected, output_buffer
449
+ end
450
+
451
+ def test_conditional_validator_filters_being_forced_and_not_meeting_condition
452
+ hash = {
453
+ :cost => {
454
+ :presence => {
455
+ :message => "can't be blank",
456
+ :unless => :cannot_validate?
457
+ }
458
+ },
459
+ :title => {
460
+ :presence => {
461
+ :message => "can't be blank",
462
+ :if => :can_validate?
463
+ }
464
+ }
465
+ }
466
+
467
+ @post.title = nil
468
+ @post.stubs(:cannot_validate?).returns(true)
469
+ @post.stubs(:can_validate?).returns(false)
470
+ @post.stubs(:client_side_validation_hash).returns(hash)
471
+ form_for(@post, :validate => true) do |f|
472
+ concat f.text_field(:cost, :validate => true)
473
+ concat f.text_field(:title, :validate => true)
474
+ end
475
+
476
+ validators = {}
477
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
478
+ %{<input id="post_cost" name="post[cost]" size="30" type="text" />} +
479
+ %{<input id="post_title" name="post[title]" size="30" type="text" />}
480
+ end
481
+ assert_equal expected, output_buffer
482
+ end
483
+
484
+ def test_conditional_validator_filters_being_forced_individually
485
+ hash = {
486
+ :cost => {
487
+ :presence => {
488
+ :message => "can't be blank",
489
+ :unless => :cannot_validate?
490
+ }
491
+ },
492
+ :title => {
493
+ :presence => {
494
+ :message => "can't be blank",
495
+ :if => :can_validate?
496
+ }
497
+ }
498
+ }
499
+
500
+ @post.title = nil
501
+ @post.stubs(:cannot_validate?).returns(false)
502
+ @post.stubs(:can_validate?).returns(true)
503
+ @post.stubs(:client_side_validation_hash).returns(hash)
504
+ form_for(@post, :validate => true) do |f|
505
+ concat f.text_field(:cost, :validate => { :presence => true })
506
+ concat f.text_field(:title, :validate => { :presence => true })
507
+ end
508
+
509
+ validators = {
510
+ 'post[cost]' => {:presence => {:message => "can't be blank"}},
511
+ 'post[title]' => {:presence => {:message => "can't be blank"}}
512
+ }
513
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
514
+ %{<input data-validate="true" id="post_cost" name="post[cost]" size="30" type="text" />} +
515
+ %{<input data-validate="true" id="post_title" name="post[title]" size="30" type="text" />}
516
+ end
517
+ assert_equal expected, output_buffer
518
+ end
519
+
520
+ def test_conditional_validator_filters_being_forced_and_not_meeting_condition_individually
521
+ hash = {
522
+ :cost => {
523
+ :presence => {
524
+ :message => "can't be blank",
525
+ :unless => :cannot_validate?
526
+ }
527
+ },
528
+ :title => {
529
+ :presence => {
530
+ :message => "can't be blank",
531
+ :if => :can_validate?
532
+ }
533
+ }
534
+ }
535
+
536
+ @post.title = nil
537
+ @post.stubs(:cannot_validate?).returns(true)
538
+ @post.stubs(:can_validate?).returns(false)
539
+ @post.stubs(:client_side_validation_hash).returns(hash)
540
+ form_for(@post, :validate => true) do |f|
541
+ concat f.text_field(:cost, :validate => { :presence => true })
542
+ concat f.text_field(:title, :validate => { :presence => true })
543
+ end
544
+
545
+ validators = {}
546
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
547
+ %{<input id="post_cost" name="post[cost]" size="30" type="text" />} +
548
+ %{<input id="post_title" name="post[title]" size="30" type="text" />}
549
+ end
550
+ assert_equal expected, output_buffer
551
+ end
552
+
553
+ def test_conditional_validator_filters_being_forced_with_procs
554
+ hash = {
555
+ :cost => {
556
+ :presence => {
557
+ :message => "can't be blank",
558
+ :unless => Proc.new { |post| post.cannot_validate? }
559
+ }
560
+ },
561
+ :title => {
562
+ :presence => {
563
+ :message => "can't be blank",
564
+ :if => Proc.new { |post| post.can_validate? }
565
+ }
566
+ }
567
+ }
568
+
569
+ @post.title = nil
570
+ @post.stubs(:cannot_validate?).returns(false)
571
+ @post.stubs(:can_validate?).returns(true)
572
+ @post.stubs(:client_side_validation_hash).returns(hash)
573
+ form_for(@post, :validate => true) do |f|
574
+ concat f.text_field(:cost, :validate => true)
575
+ concat f.text_field(:title, :validate => true)
576
+ end
577
+
578
+ validators = {
579
+ 'post[cost]' => {:presence => {:message => "can't be blank"}},
580
+ 'post[title]' => {:presence => {:message => "can't be blank"}}
581
+ }
582
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => "put", :validators => validators) do
583
+ %{<input data-validate="true" id="post_cost" name="post[cost]" size="30" type="text" />} +
584
+ %{<input data-validate="true" id="post_title" name="post[title]" size="30" type="text" />}
585
+ end
586
+ assert_equal expected, output_buffer
587
+ end
588
+
589
+ def test_pushing_script_to_content_for
590
+ form_for(@post, :validate => :post) do |f|
591
+ concat f.text_field(:cost)
592
+ end
593
+
594
+ validators = {'post[cost]' => {:presence => {:message => "can't be blank"}}}
595
+ expected = %{<form accept-charset="UTF-8" action="/posts/123" class="edit_post" data-validate="true" id="edit_post_123" method="post" novalidate="novalidate"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="_method" type="hidden" value="put" /></div><input data-validate="true" id="post_cost" name="post[cost]" size="30" type="text" /></form>}
596
+ assert_equal expected, output_buffer
597
+ assert_equal build_script_tag(nil, "edit_post_123", validators), content_for(:post)
598
+ end
336
599
  end
337
600
 
@@ -30,7 +30,7 @@ class ClientSideValidations::LegacyActionViewHelpersTest < ActionView::TestCase
30
30
  concat f.file_field(:cost)
31
31
  end
32
32
 
33
- expected = whole_form("/posts/123", "edit_post_123", "edit_post", "put") do
33
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", :method => :put, :file => true) do
34
34
  %{<input id="post_cost" name="post[cost]" type="file" />}
35
35
  end
36
36
  assert_equal expected, output_buffer
@@ -168,6 +168,17 @@ class ClientSideValidations::LegacyActionViewHelpersTest < ActionView::TestCase
168
168
  assert_equal expected, output_buffer
169
169
  end
170
170
 
171
+ def test_select_multiple
172
+ form_for(@post) do |f|
173
+ concat f.select(:cost, [], {}, :multiple => true)
174
+ end
175
+
176
+ expected = whole_form("/posts/123", "edit_post_123", "edit_post", "put") do
177
+ %{<select id="post_cost" multiple="multiple" name="post[cost][]"></select>}
178
+ end
179
+ assert_equal expected, output_buffer
180
+ end
181
+
171
182
  def test_collection_select
172
183
  form_for(@post) do |f|
173
184
  concat f.collection_select(:cost, [], :id, :name)
@@ -138,24 +138,37 @@ class ActiveModel::ValidationsTest < ClientSideValidations::ActiveModelTestBase
138
138
  assert_equal expected_hash, person.client_side_validation_hash
139
139
  end
140
140
 
141
- def test_validators_with_if_or_unless_are_ignored
141
+ def test_generic_block_validators_should_be_ignored
142
142
  person = new_person do |p|
143
- p.validates_presence_of :first_name, :if => Proc.new { |p| true }
144
- p.validates_presence_of :last_name, :unless => Proc.new { |p| true }
143
+ p.validates_each(:first_name) do |record, attr, value|
144
+ record.errors.add(:first_name, "failed")
145
+ end
145
146
  end
146
147
 
147
148
  expected_hash = {}
148
149
  assert_equal expected_hash, person.client_side_validation_hash
149
150
  end
150
151
 
151
- def test_generic_block_validators_should_be_ignored
152
+ def test_conditionals_persist_on_validator
152
153
  person = new_person do |p|
153
- p.validates_each(:first_name) do |record, attr, value|
154
- record.errors.add(:first_name, "failed")
155
- end
154
+ p.validates :first_name, :presence => { :if => :can_validate? }
155
+ p.validates :last_name, :presence => { :unless => :cannot_validate? }
156
156
  end
157
157
 
158
- expected_hash = {}
158
+ expected_hash = {
159
+ :first_name => {
160
+ :presence => {
161
+ :message => "can't be blank",
162
+ :if => :can_validate?
163
+ }
164
+ },
165
+ :last_name => {
166
+ :presence => {
167
+ :message => "can't be blank",
168
+ :unless => :cannot_validate?
169
+ }
170
+ }
171
+ }
159
172
  assert_equal expected_hash, person.client_side_validation_hash
160
173
  end
161
174
  end
@@ -30,7 +30,7 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
30
30
 
31
31
  def test_uniqueness_when_resource_exists
32
32
  User.create(:email => 'user@test.com')
33
- get '/validators/uniqueness.json', { 'user[email]' => 'user@test.com', 'case_sensitive' => true }
33
+ get '/validators/uniqueness', { 'user[email]' => 'user@test.com', 'case_sensitive' => true }
34
34
 
35
35
  assert_equal 'false', last_response.body
36
36
  assert last_response.ok?
@@ -38,14 +38,14 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
38
38
 
39
39
  def test_uniqueness_when_resource_exists_and_param_order_is_backwards
40
40
  User.create(:email => 'user@test.com')
41
- get '/validators/uniqueness.json', { 'case_sensitive' => true, 'user[email]' => 'user@test.com' }
41
+ get '/validators/uniqueness', { 'case_sensitive' => true, 'user[email]' => 'user@test.com' }
42
42
 
43
43
  assert_equal 'false', last_response.body
44
44
  assert last_response.ok?
45
45
  end
46
46
 
47
47
  def test_uniqueness_when_resource_does_not_exist
48
- get '/validators/uniqueness.json', { 'user[email]' => 'user@test.com', 'case_sensitive' => true }
48
+ get '/validators/uniqueness', { 'user[email]' => 'user@test.com', 'case_sensitive' => true }
49
49
 
50
50
  assert_equal 'true', last_response.body
51
51
  assert last_response.not_found?
@@ -53,15 +53,33 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
53
53
 
54
54
  def test_uniqueness_when_id_is_given
55
55
  user = User.create(:email => 'user@test.com')
56
- get '/validators/uniqueness.json', { 'user[email]' => 'user@test.com', 'id' => user.id, 'case_sensitive' => true }
56
+ get '/validators/uniqueness', { 'user[email]' => 'user@test.com', 'id' => user.id, 'case_sensitive' => true }
57
57
 
58
58
  assert_equal 'true', last_response.body
59
59
  assert last_response.not_found?
60
60
  end
61
61
 
62
+ def test_mysql_adapter_uniqueness_when_id_is_given
63
+ user = User.create(:email => 'user@test.com')
64
+ ActiveRecord::ConnectionAdapters::SQLite3Adapter.
65
+ any_instance.expects(:instance_variable_get).
66
+ with("@config").
67
+ returns({:adapter => "mysql"})
68
+
69
+ sql_without_binary = "#{User.arel_table["email"].eq(user.email).to_sql} AND #{User.arel_table.primary_key.not_eq(user.id).to_sql}"
70
+ relation = Arel::Nodes::SqlLiteral.new("BINARY #{sql_without_binary}")
71
+
72
+ #NOTE: Stubs User#where because SQLite3 don't know BINARY
73
+ result = User.where(sql_without_binary)
74
+ User.expects(:where).with(relation).returns(result)
75
+
76
+ get '/validators/uniqueness', { 'user[email]' => user.email, 'case_sensitive' => true, 'id' => user.id}
77
+ assert_equal 'true', last_response.body
78
+ end
79
+
62
80
  def test_uniqueness_when_scope_is_given
63
81
  User.create(:email => 'user@test.com', :age => 25)
64
- get '/validators/uniqueness.json', { 'user[email]' => 'user@test.com', 'scope' => { 'age' => 30 }, 'case_sensitive' => true }
82
+ get '/validators/uniqueness', { 'user[email]' => 'user@test.com', 'scope' => { 'age' => 30 }, 'case_sensitive' => true }
65
83
 
66
84
  assert_equal 'true', last_response.body
67
85
  assert last_response.not_found?
@@ -69,7 +87,7 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
69
87
 
70
88
  def test_uniqueness_when_multiple_scopes_are_given
71
89
  User.create(:email => 'user@test.com', :age => 30, :name => 'Brian')
72
- get '/validators/uniqueness.json', { 'user[email]' => 'user@test.com', 'scope' => { 'age' => 30, 'name' => 'Robert' }, 'case_sensitive' => true }
90
+ get '/validators/uniqueness', { 'user[email]' => 'user@test.com', 'scope' => { 'age' => 30, 'name' => 'Robert' }, 'case_sensitive' => true }
73
91
 
74
92
  assert_equal 'true', last_response.body
75
93
  assert last_response.not_found?
@@ -77,7 +95,7 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
77
95
 
78
96
  def test_uniqueness_when_case_insensitive
79
97
  User.create(:name => 'Brian')
80
- get '/validators/uniqueness.json', { 'user[name]' => 'BRIAN', 'case_sensitive' => false }
98
+ get '/validators/uniqueness', { 'user[name]' => 'BRIAN', 'case_sensitive' => false }
81
99
 
82
100
  assert_equal 'false', last_response.body
83
101
  assert last_response.ok?
@@ -85,7 +103,7 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
85
103
 
86
104
  def test_uniqueness_when_attribute_passes_as_an_integer
87
105
  User.create(:name => 123)
88
- get '/validators/uniqueness.json', { 'user[name]' => 123, 'case_sensitive' => true }
106
+ get '/validators/uniqueness', { 'user[name]' => 123, 'case_sensitive' => true }
89
107
 
90
108
  assert_equal 'false', last_response.body
91
109
  assert last_response.ok?
@@ -93,7 +111,7 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
93
111
 
94
112
  def test_uniqueness_when_attribute_passes_as_an_integer
95
113
  User.create(:name => 123)
96
- get '/validators/uniqueness.json', { 'user[name]' => 123, 'case_sensitive' => true }
114
+ get '/validators/uniqueness', { 'user[name]' => 123, 'case_sensitive' => true }
97
115
 
98
116
  assert_equal 'false', last_response.body
99
117
  assert last_response.ok?
@@ -102,14 +120,14 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
102
120
  def test_uniqueness_with_columns_which_are_sql_keywords
103
121
  Guid.validates_uniqueness_of :key
104
122
  assert_nothing_raised do
105
- get '/validators/uniqueness.json', { 'guid[key]' => 'test', 'case_sensitive' => true }
123
+ get '/validators/uniqueness', { 'guid[key]' => 'test', 'case_sensitive' => true }
106
124
  end
107
125
  end
108
126
 
109
127
  def test_uniqueness_with_limit
110
128
  # User.title is limited to 5 characters
111
129
  User.create(:title => "abcde")
112
- get '/validators/uniqueness.json', { 'user[title]' => 'abcdefgh', 'case_sensitive' => true }
130
+ get '/validators/uniqueness', { 'user[title]' => 'abcdefgh', 'case_sensitive' => true }
113
131
 
114
132
  assert_equal 'false', last_response.body
115
133
  assert last_response.ok?
@@ -119,7 +137,7 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
119
137
  with_kcode('UTF8') do
120
138
  # User.title is limited to 5 characters
121
139
  User.create(:title => "一二三四五")
122
- get '/validators/uniqueness.json', { 'user[title]' => '一二三四五六七八', 'case_sensitive' => true }
140
+ get '/validators/uniqueness', { 'user[title]' => '一二三四五六七八', 'case_sensitive' => true }
123
141
 
124
142
  assert_equal 'false', last_response.body
125
143
  assert last_response.ok?
@@ -127,24 +145,31 @@ class ClientSideValidationsActiveRecordMiddlewareTest < Test::Unit::TestCase
127
145
  end
128
146
 
129
147
  def test_validate_straight_inheritance_uniqueness
130
- get '/validators/uniqueness.json', { 'inept_wizard[name]' => 'Rincewind', 'case_sensitive' => true }
148
+ get '/validators/uniqueness', { 'inept_wizard[name]' => 'Rincewind', 'case_sensitive' => true }
131
149
  assert_equal 'true', last_response.body
132
150
  assert last_response.not_found?
133
151
 
134
152
  IneptWizard.create(:name => 'Rincewind')
135
- get '/validators/uniqueness.json', { 'inept_wizard[name]' => 'Rincewind', 'case_sensitive' => true }
153
+ get '/validators/uniqueness', { 'inept_wizard[name]' => 'Rincewind', 'case_sensitive' => true }
136
154
  assert_equal 'false', last_response.body
137
155
  assert last_response.ok?
138
156
 
139
- get '/validators/uniqueness.json', { 'conjurer[name]' => 'Rincewind', 'case_sensitive' => true }
157
+ get '/validators/uniqueness', { 'conjurer[name]' => 'Rincewind', 'case_sensitive' => true }
140
158
  assert_equal 'false', last_response.body
141
159
  assert last_response.ok?
142
160
 
143
161
  Conjurer.create(:name => 'The Amazing Bonko')
144
- get '/validators/uniqueness.json', { 'thaumaturgist[name]' => 'The Amazing Bonko', 'case_sensitive' => true }
162
+ get '/validators/uniqueness', { 'thaumaturgist[name]' => 'The Amazing Bonko', 'case_sensitive' => true }
145
163
  assert_equal 'false', last_response.body
146
164
  assert last_response.ok?
147
165
  end
148
166
 
167
+ def test_uniqueness_when_resource_is_a_nested_module
168
+ ActiveRecordTestModule::User2.create(:email => 'user@test.com')
169
+ get '/validators/uniqueness', { 'active_record_test_module/user2[email]' => 'user@test.com', 'case_sensitive' => true }
170
+
171
+ assert_equal 'false', last_response.body
172
+ assert last_response.ok?
173
+ end
149
174
  end
150
175
 
@@ -41,5 +41,10 @@ class ActiveRecord::UniquenessValidatorTest < ClientSideValidations::ActiveRecor
41
41
  assert_equal expected_hash, result_hash
42
42
  end
43
43
 
44
+ def test_uniqueness_client_side_hash_when_nested_module
45
+ @user = ActiveRecordTestModule::User2.new
46
+ expected_hash = { :message => "has already been taken", :case_sensitive => true, :class => 'active_record_test_module/user2' }
47
+ assert_equal expected_hash, UniquenessValidator.new(:attributes => [:name]).client_side_hash(@user, :name)
48
+ end
44
49
  end
45
50
 
@@ -8,3 +8,7 @@ end
8
8
  class IneptWizard < User; end
9
9
  class Conjurer < IneptWizard; end
10
10
  class Thaumaturgist < Conjurer; end
11
+
12
+ module ActiveRecordTestModule
13
+ class User2 < User; end
14
+ end
data/test/base_helper.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
2
4
  require 'ruby-debug'
3
5
  require 'test/unit'
4
6
  require 'mocha'
@@ -1,3 +1,4 @@
1
+ require 'base_helper'
1
2
  require 'client_side_validations/core_ext'
2
3
 
3
4
  class CoreExtTest < Test::Unit::TestCase
@@ -1,2 +1,7 @@
1
+ # encoding: utf-8
2
+ require 'active_support'
3
+ require 'formtastic/railtie' if defined?(::Rails)
4
+ require 'formtastic/engine' if defined?(::Rails)
1
5
  require 'formtastic'
2
6
  require 'client_side_validations/formtastic'
7
+