schema_validations 2.2.0 → 2.4.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 (37) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/prs.yml +134 -0
  3. data/.gitignore +1 -0
  4. data/.simplecov +20 -0
  5. data/.travis.yml +6 -3
  6. data/Gemfile +5 -0
  7. data/README.md +25 -6
  8. data/Rakefile +2 -0
  9. data/gemfiles/Gemfile.base +1 -1
  10. data/gemfiles/activerecord-5.2/Gemfile.base +4 -0
  11. data/gemfiles/activerecord-5.2/Gemfile.mysql2 +10 -0
  12. data/gemfiles/activerecord-5.2/Gemfile.postgresql +10 -0
  13. data/gemfiles/{activerecord-5.0 → activerecord-5.2}/Gemfile.sqlite3 +3 -3
  14. data/gemfiles/activerecord-6.0/Gemfile.base +4 -0
  15. data/gemfiles/activerecord-6.0/Gemfile.mysql2 +10 -0
  16. data/gemfiles/activerecord-6.0/Gemfile.postgresql +10 -0
  17. data/gemfiles/{activerecord-4.2 → activerecord-6.0}/Gemfile.sqlite3 +3 -3
  18. data/init.rb +2 -0
  19. data/lib/schema_validations/active_record/type.rb +2 -0
  20. data/lib/schema_validations/active_record/validations.rb +8 -1
  21. data/lib/schema_validations/railtie.rb +2 -0
  22. data/lib/schema_validations/validators/not_nil_validator.rb +13 -0
  23. data/lib/schema_validations/version.rb +3 -1
  24. data/lib/schema_validations.rb +3 -0
  25. data/schema_dev.yml +5 -3
  26. data/schema_validations.gemspec +23 -27
  27. data/spec/spec_helper.rb +22 -18
  28. data/spec/support/active_model.rb +2 -0
  29. data/spec/validations_spec.rb +138 -73
  30. metadata +38 -94
  31. data/gemfiles/activerecord-4.2/Gemfile.base +0 -3
  32. data/gemfiles/activerecord-4.2/Gemfile.mysql2 +0 -10
  33. data/gemfiles/activerecord-4.2/Gemfile.postgresql +0 -10
  34. data/gemfiles/activerecord-5.0/Gemfile.base +0 -3
  35. data/gemfiles/activerecord-5.0/Gemfile.mysql2 +0 -10
  36. data/gemfiles/activerecord-5.0/Gemfile.postgresql +0 -10
  37. data/spec/schema_validations.sqlite3 +0 -0
@@ -1,38 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
4
 
3
5
  describe "Validations" do
4
6
 
5
7
  before(:each) do
6
- ActiveRecord::Schema.define do
8
+ define_schema do
7
9
 
8
- create_table :articles, :force => true do |t|
9
- t.string :title, :limit => 50
10
- t.text :content, :null => false
10
+ create_table :articles, force: true do |t|
11
+ t.string :title, limit: 50
12
+ t.text :content, null: false
11
13
  t.integer :state
12
14
  t.integer :votes
13
- t.float :average_mark, :null => false
14
- t.boolean :active, :null => false
15
- t.decimal :max10, :precision => 2, :scale => 1
16
- t.decimal :arbitrary, :precision => nil, :scale => nil
17
- t.decimal :max100, :precision => 2, :scale => nil
15
+ t.float :average_mark, null: false
16
+ t.boolean :active, null: false
17
+ t.decimal :max10, precision: 2, scale: 1
18
+ t.decimal :arbitrary, precision: nil, scale: nil
19
+ t.decimal :max100, precision: 2, scale: nil
18
20
  end
19
- add_index :articles, :title, :unique => true
20
- add_index :articles, [:state, :active], :unique => true
21
+ add_index :articles, :title, unique: true
22
+ add_index :articles, [:state, :active], unique: true
21
23
 
22
- create_table :reviews, :force => true do |t|
23
- t.integer :article_id, :null => false
24
- t.string :author, :null => false
25
- t.string :content, :limit => 200
24
+ create_table :reviews, force: true do |t|
25
+ t.integer :article_id, null: false
26
+ t.string :author, null: false
27
+ t.string :content, limit: 200
26
28
  t.string :type
27
- t.timestamps :null => false
29
+ t.timestamps null: false
28
30
  end
29
- add_index :reviews, :article_id, :unique => true
31
+ add_index :reviews, :article_id, unique: true
30
32
 
31
- create_table :article_reviews, :force => true do |t|
33
+ create_table :article_reviews, force: true do |t|
32
34
  t.integer :article_id
33
35
  t.integer :review_id
34
36
  end
35
- add_index :article_reviews, [:article_id, :review_id], :unique => true
37
+ add_index :article_reviews, [:article_id, :review_id], unique: true
36
38
  end
37
39
  end
38
40
 
@@ -43,8 +45,8 @@ describe "Validations" do
43
45
 
44
46
  class Review < ActiveRecord::Base
45
47
  belongs_to :article
46
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
47
- schema_validations :except => :content
48
+ belongs_to :news_article, class_name: 'Article', foreign_key: :article_id
49
+ schema_validations except: :content
48
50
  end
49
51
 
50
52
  class ArticleReview < ActiveRecord::Base
@@ -81,15 +83,15 @@ describe "Validations" do
81
83
  end
82
84
 
83
85
  it "should check title length" do
84
- expect(Article.new(:title => 'a' * 100).error_on(:title).size).to eq(1)
86
+ expect(Article.new(title: 'a' * 100).error_on(:title).size).to eq(1)
85
87
  end
86
88
 
87
89
  it "should validate state numericality" do
88
- expect(Article.new(:state => 'unknown').error_on(:state).size).to eq(1)
90
+ expect(Article.new(state: 'unknown').error_on(:state).size).to eq(1)
89
91
  end
90
92
 
91
93
  it "should validate if state is integer" do
92
- expect(Article.new(:state => 1.23).error_on(:state).size).to eq(1)
94
+ expect(Article.new(state: 1.23).error_on(:state).size).to eq(1)
93
95
  end
94
96
 
95
97
  it "should validate the range of votes" do
@@ -115,28 +117,28 @@ describe "Validations" do
115
117
  expect(Article.new(max100: -100).error_on(:max100).size).to eq(1)
116
118
  end
117
119
 
118
- it "should not validate the range of arbitrary decimal", :mysql => :skip do # mysql provides a default precision
120
+ it "should not validate the range of arbitrary decimal", mysql: :skip do # mysql provides a default precision
119
121
  expect(Article.new(arbitrary: Float::MAX).error_on(:arbitrary).size).to eq(0)
120
122
  end
121
123
 
122
124
  it "should validate average_mark numericality" do
123
- expect(Article.new(:average_mark => "high").error_on(:average_mark).size).to eq(1)
125
+ expect(Article.new(average_mark: "high").error_on(:average_mark).size).to eq(1)
124
126
  end
125
127
 
126
128
  it "should validate boolean fields" do
127
- expect(Article.new(:active => nil).error_on(:active).size).to eq(1)
129
+ expect(Article.new(active: nil).error_on(:active).size).to eq(1)
128
130
  end
129
131
 
130
132
  it "should validate title uniqueness" do
131
133
  article1 = Article.create(valid_article_attributes)
132
- article2 = Article.new(:title => valid_article_attributes[:title])
134
+ article2 = Article.new(title: valid_article_attributes[:title])
133
135
  expect(article2.error_on(:title).size).to eq(1)
134
136
  article1.destroy
135
137
  end
136
138
 
137
139
  it "should validate state uniqueness in scope of 'active' value" do
138
140
  article1 = Article.create(valid_article_attributes)
139
- article2 = Article.new(valid_article_attributes.merge(:title => 'SchemaPlus 2.0 released'))
141
+ article2 = Article.new(valid_article_attributes.merge(title: 'SchemaPlus 2.0 released'))
140
142
  expect(article2).not_to be_valid
141
143
  article2.toggle(:active)
142
144
  expect(article2).to be_valid
@@ -151,9 +153,9 @@ describe "Validations" do
151
153
  it "should validate uniqueness of belongs_to association" do
152
154
  article = Article.create(valid_article_attributes)
153
155
  expect(article).to be_valid
154
- review1 = Review.create(:article => article, :author => 'michal')
156
+ review1 = Review.create(article: article, author: 'michal')
155
157
  expect(review1).to be_valid
156
- review2 = Review.new(:article => article, :author => 'michal')
158
+ review2 = Review.new(article: article, author: 'michal')
157
159
  expect(review2.error_on(:article_id).size).to be >= 1
158
160
  end
159
161
 
@@ -162,18 +164,81 @@ describe "Validations" do
162
164
  end
163
165
 
164
166
  it "should not validate uniqueness when scope is absent" do
165
- article_review_1 = ArticleReview.create(:article_id => 1, :review_id => nil)
167
+ article_review_1 = ArticleReview.create(article_id: 1, review_id: nil)
166
168
  expect(article_review_1).to be_valid
167
169
 
168
- article_review_2 = ArticleReview.create(:article_id => 1, :review_id => nil)
170
+ article_review_2 = ArticleReview.create(article_id: 1, review_id: nil)
169
171
  expect(article_review_2).to be_valid
170
172
 
171
- article_review_3 = ArticleReview.create(:article_id => nil, :review_id => 1)
173
+ article_review_3 = ArticleReview.create(article_id: nil, review_id: 1)
172
174
  expect(article_review_3).to be_valid
173
175
 
174
- article_review_4 = ArticleReview.create(:article_id => nil, :review_id => 1)
176
+ article_review_4 = ArticleReview.create(article_id: nil, review_id: 1)
175
177
  expect(article_review_4).to be_valid
176
178
  end
179
+
180
+ context 'when NOT NULL validations' do
181
+ before(:each) do
182
+ ActiveRecord::Schema.define do
183
+ create_table :anti_nulls, force: true do |t|
184
+ t.string :no_default, null: false
185
+ t.string :blank_default, default: '', null: false
186
+ t.string :non_blank_default, default: 'not blank', null: false
187
+ end
188
+ end
189
+ with_auto_validations do
190
+ class AntiNull < ActiveRecord::Base
191
+ def self.all_blank
192
+ @all_blank ||= AntiNull.new(
193
+ no_default: '',
194
+ blank_default: '',
195
+ non_blank_default: ''
196
+ )
197
+ end
198
+
199
+ def self.all_non_blank
200
+ @all_non_blank ||= AntiNull.new(
201
+ no_default: 'foo',
202
+ blank_default: 'bar',
203
+ non_blank_default: 'baz'
204
+ )
205
+ end
206
+
207
+ def self.all_nil
208
+ @all_nil ||= AntiNull.new(
209
+ no_default: nil,
210
+ blank_default: nil,
211
+ non_blank_default: nil
212
+ )
213
+ end
214
+
215
+ def self.non_null_with(**fields)
216
+ opts = { no_default: 'foo' }.merge!(fields)
217
+ AntiNull.new **opts
218
+ end
219
+ end
220
+ end
221
+
222
+
223
+ end
224
+
225
+ it 'should fail validation on empty fields only if the default value is not blank' do
226
+ expect(AntiNull.all_nil.error_on(:no_default).size).to eq(1)
227
+ expect(AntiNull.all_nil.error_on(:blank_default).size).to eq(1)
228
+ expect(AntiNull.all_nil.error_on(:non_blank_default).size).to eq(1)
229
+ end
230
+
231
+ it 'should fail validation on empty fields only if the default value is not blank' do
232
+ expect(AntiNull.all_blank.error_on(:no_default).size).to eq(1)
233
+ expect(AntiNull.all_blank.error_on(:non_blank_default).size).to eq(1)
234
+ expect(AntiNull.all_blank.error_on(:blank_default)).to be_empty
235
+ end
236
+
237
+ it 'should not fail if fields are neither nil nor empty' do
238
+ expect(AntiNull.all_non_blank).to be_valid
239
+ end
240
+
241
+ end
177
242
  end
178
243
 
179
244
  context "auto-created but changed" do
@@ -182,62 +247,62 @@ describe "Validations" do
182
247
  class Article < ActiveRecord::Base ; end
183
248
  class Review < ActiveRecord::Base
184
249
  belongs_to :article
185
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
250
+ belongs_to :news_article, class_name: 'Article', foreign_key: :article_id
186
251
  end
187
252
  end
188
253
  @too_big_content = 'a' * 1000
189
254
  end
190
255
 
191
256
  it "would normally have an error" do
192
- @review = Review.new(:content => @too_big_content)
257
+ @review = Review.new(content: @too_big_content)
193
258
  expect(@review.error_on(:content).size).to eq(1)
194
259
  expect(@review.error_on(:author).size).to eq(1)
195
260
  end
196
261
 
197
262
  it "shouldn't validate fields passed to :except option" do
198
- Review.schema_validations :except => :content
199
- @review = Review.new(:content => @too_big_content)
263
+ Review.schema_validations except: :content
264
+ @review = Review.new(content: @too_big_content)
200
265
  expect(@review.errors_on(:content).size).to eq(0)
201
266
  expect(@review.error_on(:author).size).to eq(1)
202
267
  end
203
268
 
204
269
  it "shouldn't validate the fields in default whitelist" do
205
- Review.schema_validations :except => :content
270
+ Review.schema_validations except: :content
206
271
  expect(Review.new.error_on(:updated_at).size).to eq(0)
207
272
  expect(Review.new.error_on(:created_at).size).to eq(0)
208
273
  end
209
274
 
210
275
  it "shouldn't validate the fields in whitelist" do
211
- Review.schema_validations :except => :content, whitelist: [:updated_at]
276
+ Review.schema_validations except: :content, whitelist: [:updated_at]
212
277
  expect(Review.new.error_on(:updated_at).size).to eq(0)
213
278
  expect(Review.new.error_on(:created_at).size).to eq(1)
214
279
  end
215
280
 
216
281
  it "shouldn't validate types passed to :except_type option using full validation" do
217
- Review.schema_validations :except_type => :validates_length_of
218
- @review = Review.new(:content => @too_big_content)
282
+ Review.schema_validations except_type: :validates_length_of
283
+ @review = Review.new(content: @too_big_content)
219
284
  expect(@review.errors_on(:content).size).to eq(0)
220
285
  expect(@review.error_on(:author).size).to eq(1)
221
286
  end
222
287
 
223
288
  it "shouldn't validate types passed to :except_type option using shorthand" do
224
- Review.schema_validations :except_type => :length
225
- @review = Review.new(:content => @too_big_content)
289
+ Review.schema_validations except_type: :length
290
+ @review = Review.new(content: @too_big_content)
226
291
  expect(@review.errors_on(:content).size).to eq(0)
227
292
  expect(@review.error_on(:author).size).to eq(1)
228
293
  end
229
294
 
230
295
  it "should only validate type passed to :only_type option" do
231
- Review.schema_validations :only_type => :length
232
- @review = Review.new(:content => @too_big_content)
296
+ Review.schema_validations only_type: :length
297
+ @review = Review.new(content: @too_big_content)
233
298
  expect(@review.error_on(:content).size).to eq(1)
234
299
  expect(@review.errors_on(:author).size).to eq(0)
235
300
  end
236
301
 
237
302
 
238
303
  it "shouldn't create validations if locally disabled" do
239
- Review.schema_validations :auto_create => false
240
- @review = Review.new(:content => @too_big_content)
304
+ Review.schema_validations auto_create: false
305
+ @review = Review.new(content: @too_big_content)
241
306
  expect(@review.errors_on(:content).size).to eq(0)
242
307
  expect(@review.error_on(:author).size).to eq(0)
243
308
  end
@@ -251,23 +316,23 @@ describe "Validations" do
251
316
  before(:each) do
252
317
  class Review < ActiveRecord::Base
253
318
  belongs_to :article
254
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
319
+ belongs_to :news_article, class_name: 'Article', foreign_key: :article_id
255
320
  end
256
321
  @too_big_content = 'a' * 1000
257
322
  end
258
323
 
259
324
  it "should not create validation" do
260
- expect(Review.new(:content => @too_big_title).errors_on(:content).size).to eq(0)
325
+ expect(Review.new(content: @too_big_title).errors_on(:content).size).to eq(0)
261
326
  end
262
327
 
263
328
  it "should create validation if locally enabled explicitly" do
264
- Review.schema_validations :auto_create => true
265
- expect(Review.new(:content => @too_big_content).error_on(:content).size).to eq(1)
329
+ Review.schema_validations auto_create: true
330
+ expect(Review.new(content: @too_big_content).error_on(:content).size).to eq(1)
266
331
  end
267
332
 
268
333
  it "should create validation if locally enabled implicitly" do
269
334
  Review.schema_validations
270
- expect(Review.new(:content => @too_big_content).error_on(:content).size).to eq(1)
335
+ expect(Review.new(content: @too_big_content).error_on(:content).size).to eq(1)
271
336
  end
272
337
 
273
338
  end
@@ -275,18 +340,18 @@ describe "Validations" do
275
340
  context "manually invoked" do
276
341
  before(:each) do
277
342
  class Article < ActiveRecord::Base ; end
278
- Article.schema_validations :only => [:title, :state]
343
+ Article.schema_validations only: [:title, :state]
279
344
 
280
345
  class Review < ActiveRecord::Base
281
346
  belongs_to :dummy_association
282
- schema_validations :except => :content
347
+ schema_validations except: :content
283
348
  end
284
349
  end
285
350
 
286
351
  it "should validate fields passed to :only option" do
287
352
  too_big_title = 'a' * 100
288
353
  wrong_state = 'unknown'
289
- article = Article.new(:title => too_big_title, :state => wrong_state)
354
+ article = Article.new(title: too_big_title, state: wrong_state)
290
355
  expect(article.error_on(:title).size).to eq(1)
291
356
  expect(article.error_on(:state).size).to eq(1)
292
357
  end
@@ -317,7 +382,7 @@ describe "Validations" do
317
382
  belongs_to :article
318
383
  end
319
384
  @columns = Review.content_columns.dup
320
- Review.schema_validations :only => [:title]
385
+ Review.schema_validations only: [:title]
321
386
  end
322
387
 
323
388
  it "shouldn't validate associations not included in :only option" do
@@ -352,9 +417,9 @@ describe "Validations" do
352
417
  context "when used with enum" do
353
418
  it "does not validate numericality" do
354
419
  class Article < ActiveRecord::Base
355
- enum :state => [:happy, :sad]
420
+ enum state: [:happy, :sad]
356
421
  end
357
- expect(Article.new(valid_article_attributes.merge(:state => :happy))).to be_valid
422
+ expect(Article.new(valid_article_attributes.merge(state: :happy))).to be_valid
358
423
  end
359
424
  end if ActiveRecord::Base.respond_to? :enum
360
425
 
@@ -366,11 +431,11 @@ describe "Validations" do
366
431
  context 'without scope' do
367
432
  before do
368
433
  ActiveRecord::Schema.define do
369
- create_table :books, :force => true do |t|
434
+ create_table :books, force: true do |t|
370
435
  t.string :title
371
436
  end
372
437
 
373
- add_index :books, :title, :unique => true
438
+ add_index :books, :title, unique: true
374
439
  end
375
440
 
376
441
  with_auto_validations do
@@ -390,12 +455,12 @@ describe "Validations" do
390
455
  context 'within a scope' do
391
456
  before do
392
457
  ActiveRecord::Schema.define do
393
- create_table :folders, :force => true do |t|
458
+ create_table :folders, force: true do |t|
394
459
  t.integer :parent_id
395
460
  t.string :name
396
461
  end
397
462
 
398
- add_index :folders, [:parent_id, :name], :unique => true
463
+ add_index :folders, [:parent_id, :name], unique: true
399
464
  end
400
465
 
401
466
  with_auto_validations do
@@ -408,10 +473,10 @@ describe "Validations" do
408
473
  it "should validate the uniqueness in a case insensitive manner" do
409
474
  mixed_case_name = 'Schema Validations'
410
475
  parent_folder = Folder.create
411
- Folder.create(:parent => parent_folder, :name => mixed_case_name)
476
+ Folder.create(parent: parent_folder, name: mixed_case_name)
412
477
 
413
- expect(Folder.new(:parent => parent_folder, :name => mixed_case_name)).not_to be_valid
414
- expect(Folder.new(:parent => parent_folder, :name => mixed_case_name.downcase)).not_to be_valid
478
+ expect(Folder.new(parent: parent_folder, name: mixed_case_name)).not_to be_valid
479
+ expect(Folder.new(parent: parent_folder, name: mixed_case_name.downcase)).not_to be_valid
415
480
  end
416
481
  end
417
482
  end
@@ -419,7 +484,7 @@ describe "Validations" do
419
484
  context 'with optimistic locking' do
420
485
  before do
421
486
  ActiveRecord::Schema.define do
422
- create_table :optimistics, :force => true do |t|
487
+ create_table :optimistics, force: true do |t|
423
488
  t.integer :lock_version
424
489
  end
425
490
  end
@@ -448,11 +513,11 @@ describe "Validations" do
448
513
 
449
514
  def valid_article_attributes
450
515
  {
451
- :title => 'SchemaPlus released!',
452
- :content => "Database matters. Get full use of it but don't write unecessary code. Get SchemaPlus!",
453
- :state => 3,
454
- :average_mark => 9.78,
455
- :active => true
516
+ title: 'SchemaPlus released!',
517
+ content: "Database matters. Get full use of it but don't write unecessary code. Get SchemaPlus!",
518
+ state: 3,
519
+ average_mark: 9.78,
520
+ active: true
456
521
  }
457
522
  end
458
523