activerecord_mysql_strict 0.2 → 0.2.1
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.
- checksums.yaml +7 -0
- data/README.md +1 -0
- data/lib/active_record/mysql/strict/validation.rb +25 -0
- data/lib/active_record/mysql/strict/validation/integer_validation.rb +16 -0
- data/lib/active_record/mysql/strict/validation/string_validation.rb +15 -0
- data/lib/active_record/mysql/strict/validation/text_validation.rb +15 -0
- data/lib/active_record/mysql/strict/validator/strict_length_validator.rb +30 -0
- data/lib/active_record/mysql/strict/version.rb +1 -1
- data/lib/activerecord_mysql_strict.rb +11 -3
- data/spec/activerecord_mysql_strict/validation/integer_validation_spec.rb +27 -0
- data/spec/activerecord_mysql_strict/validation/string_validation_spec.rb +121 -0
- data/spec/activerecord_mysql_strict/validation/text_validation_spec.rb +50 -0
- data/spec/activerecord_mysql_strict/validation_spec.rb +7 -0
- data/spec/activerecord_mysql_strict_spec.rb +2 -2
- metadata +30 -43
- data/lib/active_record/mysql/strict/strict_length_validator.rb +0 -28
- data/lib/active_record/mysql/strict/validations.rb +0 -40
- data/spec/activerecord_mysql_strict/validations_spec.rb +0 -186
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7d2ab7d2a8b48a070e7ba2bf8f3301754325e69b
|
4
|
+
data.tar.gz: 05c68f36aa4d65ebea6323752cc8e8c98b525247
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b3a1af02f69c83b3e0a6e171360b7d425306cb908b0d9c4ee585a2823c9fc58cf81d16287253d87e4f8c7d1c023a70b85aa56c6757845c77f5698d4e392fa005
|
7
|
+
data.tar.gz: c2165ac3947567b7c9bb6e679b3b17fed31a312bd18a0cf3e196f02b67e96bd097b84475700fb1aacad570f76f57a395f3d92280a8c65a721b0a6d26340e6b42
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# ActiveRecord::MySQL::Strict
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/activerecord_mysql_strict)
|
4
|
+
[](https://codeclimate.com/github/mirego/activerecord_mysql_strict)
|
4
5
|
[](https://travis-ci.org/mirego/activerecord_mysql_strict)
|
5
6
|
|
6
7
|
`ActiveRecord::MySQL::Strict` adds validations to ActiveRecord models to make sure they do not trigger errors in MySQL strict mode.
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module MySQL
|
3
|
+
module Strict
|
4
|
+
class Validation < Struct.new(:model, :field)
|
5
|
+
# Inject validations into an ActiveRecord model
|
6
|
+
def self.inject_validations(model, options = {})
|
7
|
+
except = options[:except] || []
|
8
|
+
model_columns = model.columns.dup.reject { |c| except.include?(c.name.to_sym) }
|
9
|
+
|
10
|
+
if only = options[:only]
|
11
|
+
model_columns = model_columns.select { |c| only.include?(c.name.to_sym) }
|
12
|
+
end
|
13
|
+
|
14
|
+
model_columns.each do |field|
|
15
|
+
validation = "#{field.type.to_s.camelize}Validation"
|
16
|
+
|
17
|
+
if ActiveRecord::MySQL::Strict::Validation.const_defined?(validation)
|
18
|
+
"ActiveRecord::MySQL::Strict::Validation::#{validation}".constantize.new(model, field).apply
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module MySQL
|
3
|
+
module Strict
|
4
|
+
class Validation
|
5
|
+
class IntegerValidation < Validation
|
6
|
+
UPPER_LIMIT = 2147483647
|
7
|
+
LOWER_LIMIT = -2147483647
|
8
|
+
|
9
|
+
def apply
|
10
|
+
model.validates field.name, numericality: { greather_than_or_equal_to: LOWER_LIMIT, less_than_or_equal_to: UPPER_LIMIT }, allow_blank: true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module MySQL
|
3
|
+
module Strict
|
4
|
+
class Validation
|
5
|
+
class StringValidation < Validation
|
6
|
+
LIMIT = 255
|
7
|
+
|
8
|
+
def apply
|
9
|
+
model.validates field.name, 'ActiveRecord::MySQL::Strict::Validator::StrictLength' => { in: 0..(field.limit || LIMIT) }, allow_blank: true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module MySQL
|
3
|
+
module Strict
|
4
|
+
class Validation
|
5
|
+
class TextValidation < Validation
|
6
|
+
LIMIT = 65535
|
7
|
+
|
8
|
+
def apply
|
9
|
+
model.validates field.name, 'ActiveRecord::MySQL::Strict::Validator::StrictLength' => { in: 0..(field.limit || LIMIT) }, allow_blank: true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module MySQL
|
3
|
+
module Strict
|
4
|
+
module Validator
|
5
|
+
class StrictLengthValidator < ActiveModel::Validations::LengthValidator
|
6
|
+
def validate_each(record, attribute, value)
|
7
|
+
value = record.send(:read_attribute, attribute)
|
8
|
+
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
|
9
|
+
errors_options = options.except(*RESERVED_OPTIONS)
|
10
|
+
|
11
|
+
CHECKS.each do |key, validity_check|
|
12
|
+
next unless check_value = options[key]
|
13
|
+
|
14
|
+
if !value.nil? || skip_nil_check?(key)
|
15
|
+
next if value_length.send(validity_check, check_value)
|
16
|
+
end
|
17
|
+
|
18
|
+
errors_options[:count] = check_value
|
19
|
+
|
20
|
+
default_message = options[MESSAGES[key]]
|
21
|
+
errors_options[:message] ||= default_message if default_message
|
22
|
+
|
23
|
+
record.errors.add(attribute, MESSAGES[key], errors_options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -4,11 +4,19 @@ require 'active_record'
|
|
4
4
|
require 'active_model'
|
5
5
|
require 'active_support'
|
6
6
|
|
7
|
-
|
8
|
-
require 'active_record/mysql/strict/
|
7
|
+
# Validators
|
8
|
+
require 'active_record/mysql/strict/validator/strict_length_validator'
|
9
|
+
|
10
|
+
# Validations
|
11
|
+
require 'active_record/mysql/strict/validation'
|
12
|
+
require 'active_record/mysql/strict/validation/string_validation'
|
13
|
+
require 'active_record/mysql/strict/validation/text_validation'
|
14
|
+
require 'active_record/mysql/strict/validation/integer_validation'
|
9
15
|
|
10
16
|
class ActiveRecord::Base
|
11
17
|
def self.validates_strict_columns(options = {})
|
12
|
-
|
18
|
+
if table_exists?
|
19
|
+
ActiveRecord::MySQL::Strict::Validation.inject_validations(self, options)
|
20
|
+
end
|
13
21
|
end
|
14
22
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRecord::MySQL::Strict::Validation::IntegerValidation do
|
4
|
+
describe :apply do
|
5
|
+
context 'for model without other validations' do
|
6
|
+
let(:model) { strict_model 'User' }
|
7
|
+
|
8
|
+
context 'with field with default limit' do
|
9
|
+
before do
|
10
|
+
run_migration do
|
11
|
+
create_table(:users, force: true) { |t| t.integer :number }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with field value exceeding limit' do
|
16
|
+
subject { model.new(number: 9999999999) }
|
17
|
+
it { should_not be_valid }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with field value not exceeding limit' do
|
21
|
+
subject { model.new(number: 2147483647) }
|
22
|
+
it { should be_valid }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRecord::MySQL::Strict::Validation::StringValidation do
|
4
|
+
describe :apply do
|
5
|
+
context 'for model without other validations' do
|
6
|
+
let(:model) { strict_model 'User' }
|
7
|
+
|
8
|
+
context 'with field with default limit' do
|
9
|
+
before do
|
10
|
+
run_migration do
|
11
|
+
create_table(:users, force: true) { |t| t.string :name }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with field value exceeding limit' do
|
16
|
+
subject { model.new(name: '*' * 400) }
|
17
|
+
it { should_not be_valid }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with field value not exceeding limit' do
|
21
|
+
subject { model.new(name: '*' * 100) }
|
22
|
+
it { should be_valid }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with field with custom limit' do
|
27
|
+
before do
|
28
|
+
run_migration do
|
29
|
+
create_table(:users, force: true) { |t| t.string :name, limit: 128 }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with field value exceeding default limit' do
|
34
|
+
subject { model.new(name: '*' * 400) }
|
35
|
+
it { should_not be_valid }
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with field value exceeding custom limit' do
|
39
|
+
subject { model.new(name: '*' * 140) }
|
40
|
+
it { should_not be_valid }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with field value not exceeding custom limit' do
|
44
|
+
subject { model.new(name: '*' * 120) }
|
45
|
+
it { should be_valid }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'for model with related validations' do
|
51
|
+
context 'for presence validation' do
|
52
|
+
let(:model) do
|
53
|
+
strict_model('User') { validates :name, presence: true }
|
54
|
+
end
|
55
|
+
|
56
|
+
before do
|
57
|
+
run_migration do
|
58
|
+
create_table(:users, force: true) { |t| t.string :name }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
subject { model.new.tap(&:valid?) }
|
63
|
+
it { expect(subject.errors.full_messages).to eql ["Name can't be blank"] }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'for valid model with accessor that returns an invalid string' do
|
68
|
+
let(:model) do
|
69
|
+
strict_model 'User' do
|
70
|
+
attr_reader :long_name
|
71
|
+
|
72
|
+
# When we call `#long_name` it will return an invalid string but
|
73
|
+
# we want the attribute to store the real, valid value because we
|
74
|
+
# want to actually make sure that the real attribute value does
|
75
|
+
# not exceed the limit, not what the accessor returns.
|
76
|
+
define_method :long_name= do |value|
|
77
|
+
@long_name = '*' * 400
|
78
|
+
write_attribute(:long_name, value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
before do
|
84
|
+
run_migration do
|
85
|
+
create_table(:users, force: true) { |t| t.string :long_name }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
subject { model.new(long_name: '*' * 10) }
|
90
|
+
its(:long_name) { should eql '*' * 400 }
|
91
|
+
it { should be_valid }
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'for invalid model with accessor that returns a valid string' do
|
95
|
+
let(:model) do
|
96
|
+
strict_model 'User' do
|
97
|
+
attr_reader :short_name
|
98
|
+
|
99
|
+
# When we call `#short_name` it will return a valid string but
|
100
|
+
# we want the attribute to store the real, valid value because we
|
101
|
+
# want to actually make sure that the real attribute value does
|
102
|
+
# exceed the limit, not what the accessor returns.
|
103
|
+
define_method :short_name= do |value|
|
104
|
+
@short_name = '*' * 100
|
105
|
+
write_attribute(:short_name, value)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
before do
|
111
|
+
run_migration do
|
112
|
+
create_table(:users, force: true) { |t| t.string :short_name }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
subject { model.new(short_name: '*' * 400) }
|
117
|
+
its(:short_name) { should eql '*' * 100 }
|
118
|
+
it { should_not be_valid }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRecord::MySQL::Strict::Validation::TextValidation do
|
4
|
+
describe :apply do
|
5
|
+
context 'for model without other validations' do
|
6
|
+
let(:model) { strict_model 'User' }
|
7
|
+
|
8
|
+
context 'with field with default limit' do
|
9
|
+
before do
|
10
|
+
run_migration do
|
11
|
+
create_table(:users, force: true) { |t| t.text :bio }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with field value exceeding limit' do
|
16
|
+
subject { model.new(bio: '*' * 70000) }
|
17
|
+
it { should_not be_valid }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with field value not exceeding limit' do
|
21
|
+
subject { model.new(bio: '*' * 4000) }
|
22
|
+
it { should be_valid }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with field with custom limit' do
|
27
|
+
before do
|
28
|
+
run_migration do
|
29
|
+
create_table(:users, force: true) { |t| t.text :bio, limit: 10000 }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with field value exceeding default limit' do
|
34
|
+
subject { model.new(bio: '*' * 70000) }
|
35
|
+
it { should_not be_valid }
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with field value exceeding custom limit' do
|
39
|
+
subject { model.new(bio: '*' * 12000) }
|
40
|
+
it { should_not be_valid }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with field value not exceeding custom limit' do
|
44
|
+
subject { model.new(bio: '*' * 4000) }
|
45
|
+
it { should be_valid }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -11,7 +11,7 @@ describe ActiveRecord::MySQL::Strict do
|
|
11
11
|
|
12
12
|
context 'without options' do
|
13
13
|
before do
|
14
|
-
expect(ActiveRecord::MySQL::Strict::
|
14
|
+
expect(ActiveRecord::MySQL::Strict::Validation).to receive(:inject_validations).with(User, {})
|
15
15
|
end
|
16
16
|
|
17
17
|
it { User.validates_strict_columns }
|
@@ -19,7 +19,7 @@ describe ActiveRecord::MySQL::Strict do
|
|
19
19
|
|
20
20
|
context 'with options' do
|
21
21
|
before do
|
22
|
-
expect(ActiveRecord::MySQL::Strict::
|
22
|
+
expect(ActiveRecord::MySQL::Strict::Validation).to receive(:inject_validations).with(User, { except: [:bar], only: [:foo] })
|
23
23
|
end
|
24
24
|
|
25
25
|
it { User.validates_strict_columns except: [:bar], only: [:foo] }
|
metadata
CHANGED
@@ -1,68 +1,60 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord_mysql_strict
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Rémi Prévost
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-09-05 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activerecord
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 3.0.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 3.0.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: activemodel
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 3.0.0
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 3.0.0
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: activesupport
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 3.0.0
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 3.0.0
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: bundler
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ~>
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ~>
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,7 +69,6 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: rspec
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ~>
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ~>
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -94,33 +83,29 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: rake
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
|
-
- -
|
87
|
+
- - '>='
|
100
88
|
- !ruby/object:Gem::Version
|
101
89
|
version: '0'
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
|
-
- -
|
94
|
+
- - '>='
|
108
95
|
- !ruby/object:Gem::Version
|
109
96
|
version: '0'
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: sqlite3
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
|
-
- -
|
101
|
+
- - '>='
|
116
102
|
- !ruby/object:Gem::Version
|
117
103
|
version: '0'
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
|
-
- -
|
108
|
+
- - '>='
|
124
109
|
- !ruby/object:Gem::Version
|
125
110
|
version: '0'
|
126
111
|
description: ActiveRecord::MySQL::Strict adds validations to ActiveRecord models to
|
@@ -140,11 +125,17 @@ files:
|
|
140
125
|
- activerecord_mysql_strict.gemspec
|
141
126
|
- gemfiles/Gemfile.activerecord-3.2.x
|
142
127
|
- gemfiles/Gemfile.activerecord-4.0
|
143
|
-
- lib/active_record/mysql/strict/
|
144
|
-
- lib/active_record/mysql/strict/
|
128
|
+
- lib/active_record/mysql/strict/validation.rb
|
129
|
+
- lib/active_record/mysql/strict/validation/integer_validation.rb
|
130
|
+
- lib/active_record/mysql/strict/validation/string_validation.rb
|
131
|
+
- lib/active_record/mysql/strict/validation/text_validation.rb
|
132
|
+
- lib/active_record/mysql/strict/validator/strict_length_validator.rb
|
145
133
|
- lib/active_record/mysql/strict/version.rb
|
146
134
|
- lib/activerecord_mysql_strict.rb
|
147
|
-
- spec/activerecord_mysql_strict/
|
135
|
+
- spec/activerecord_mysql_strict/validation/integer_validation_spec.rb
|
136
|
+
- spec/activerecord_mysql_strict/validation/string_validation_spec.rb
|
137
|
+
- spec/activerecord_mysql_strict/validation/text_validation_spec.rb
|
138
|
+
- spec/activerecord_mysql_strict/validation_spec.rb
|
148
139
|
- spec/activerecord_mysql_strict_spec.rb
|
149
140
|
- spec/spec_helper.rb
|
150
141
|
- spec/support/macros/database_macros.rb
|
@@ -152,37 +143,33 @@ files:
|
|
152
143
|
homepage: https://github.com/mirego/activerecord_mysql_strict
|
153
144
|
licenses:
|
154
145
|
- BSD 3-Clause
|
146
|
+
metadata: {}
|
155
147
|
post_install_message:
|
156
148
|
rdoc_options: []
|
157
149
|
require_paths:
|
158
150
|
- lib
|
159
151
|
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
-
none: false
|
161
152
|
requirements:
|
162
|
-
- -
|
153
|
+
- - '>='
|
163
154
|
- !ruby/object:Gem::Version
|
164
155
|
version: '0'
|
165
|
-
segments:
|
166
|
-
- 0
|
167
|
-
hash: -2194545616864898002
|
168
156
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
157
|
requirements:
|
171
|
-
- -
|
158
|
+
- - '>='
|
172
159
|
- !ruby/object:Gem::Version
|
173
160
|
version: '0'
|
174
|
-
segments:
|
175
|
-
- 0
|
176
|
-
hash: -2194545616864898002
|
177
161
|
requirements: []
|
178
162
|
rubyforge_project:
|
179
|
-
rubygems_version:
|
163
|
+
rubygems_version: 2.0.2
|
180
164
|
signing_key:
|
181
|
-
specification_version:
|
165
|
+
specification_version: 4
|
182
166
|
summary: ActiveRecord::MySQL::Strict adds validations to ActiveRecord models to make
|
183
167
|
sure they do not trigger errors in MySQL strict mode.
|
184
168
|
test_files:
|
185
|
-
- spec/activerecord_mysql_strict/
|
169
|
+
- spec/activerecord_mysql_strict/validation/integer_validation_spec.rb
|
170
|
+
- spec/activerecord_mysql_strict/validation/string_validation_spec.rb
|
171
|
+
- spec/activerecord_mysql_strict/validation/text_validation_spec.rb
|
172
|
+
- spec/activerecord_mysql_strict/validation_spec.rb
|
186
173
|
- spec/activerecord_mysql_strict_spec.rb
|
187
174
|
- spec/spec_helper.rb
|
188
175
|
- spec/support/macros/database_macros.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module MySQL
|
3
|
-
module Strict
|
4
|
-
class StrictLengthValidator < ActiveModel::Validations::LengthValidator
|
5
|
-
def validate_each(record, attribute, value)
|
6
|
-
value = record.send(:read_attribute, attribute)
|
7
|
-
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
|
8
|
-
errors_options = options.except(*RESERVED_OPTIONS)
|
9
|
-
|
10
|
-
CHECKS.each do |key, validity_check|
|
11
|
-
next unless check_value = options[key]
|
12
|
-
|
13
|
-
if !value.nil? || skip_nil_check?(key)
|
14
|
-
next if value_length.send(validity_check, check_value)
|
15
|
-
end
|
16
|
-
|
17
|
-
errors_options[:count] = check_value
|
18
|
-
|
19
|
-
default_message = options[MESSAGES[key]]
|
20
|
-
errors_options[:message] ||= default_message if default_message
|
21
|
-
|
22
|
-
record.errors.add(attribute, MESSAGES[key], errors_options)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module MySQL
|
3
|
-
module Strict
|
4
|
-
module Validations
|
5
|
-
# Constants
|
6
|
-
MYSQL_STRICT_STRING_LIMIT = 255
|
7
|
-
MYSQL_STRICT_TEXT_LIMIT = 65535
|
8
|
-
MYSQL_STRICT_INTEGER_LIMIT = 2147483647
|
9
|
-
|
10
|
-
def self.define_mysql_strict_validations(klass, options = {})
|
11
|
-
except = options[:except] || []
|
12
|
-
model_columns = klass.columns.dup.reject { |c| except.include?(c.name.to_sym) }
|
13
|
-
|
14
|
-
if only = options[:only]
|
15
|
-
model_columns = model_columns.select { |c| only.include?(c.name.to_sym) }
|
16
|
-
end
|
17
|
-
|
18
|
-
model_columns.each do |field|
|
19
|
-
method = :"define_mysql_strict_#{field.type}_validation"
|
20
|
-
Validations.send(method, klass, field) if Validations.respond_to?(method)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
|
26
|
-
def self.define_mysql_strict_string_validation(klass, field)
|
27
|
-
klass.validates field.name, 'ActiveRecord::MySQL::Strict::StrictLength' => { in: 0..(field.limit || MYSQL_STRICT_STRING_LIMIT) }, allow_blank: true
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.define_mysql_strict_text_validation(klass, field)
|
31
|
-
klass.validates field.name, 'ActiveRecord::MySQL::Strict::StrictLength' => { in: 0..(field.limit || MYSQL_STRICT_TEXT_LIMIT) }, allow_blank: true
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.define_mysql_strict_integer_validation(klass, field)
|
35
|
-
klass.validates field.name, numericality: { greather_than_or_equal_to: -MYSQL_STRICT_INTEGER_LIMIT, less_than_or_equal_to: MYSQL_STRICT_INTEGER_LIMIT }, allow_blank: true
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,186 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ActiveRecord::MySQL::Strict::Validations do
|
4
|
-
describe :define_mysql_strict_validations do
|
5
|
-
context 'for model without other validations' do
|
6
|
-
let(:model) { strict_model 'User' }
|
7
|
-
|
8
|
-
context 'for `string` columns' do
|
9
|
-
context 'with field with default limit' do
|
10
|
-
before do
|
11
|
-
run_migration do
|
12
|
-
create_table(:users, force: true) { |t| t.string :name }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
context 'with field value exceeding limit' do
|
17
|
-
subject { model.new(name: '*' * 400) }
|
18
|
-
it { should_not be_valid }
|
19
|
-
end
|
20
|
-
|
21
|
-
context 'with field value not exceeding limit' do
|
22
|
-
subject { model.new(name: '*' * 100) }
|
23
|
-
it { should be_valid }
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
context 'with field with custom limit' do
|
28
|
-
before do
|
29
|
-
run_migration do
|
30
|
-
create_table(:users, force: true) { |t| t.string :name, limit: 128 }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
context 'with field value exceeding default limit' do
|
35
|
-
subject { model.new(name: '*' * 400) }
|
36
|
-
it { should_not be_valid }
|
37
|
-
end
|
38
|
-
|
39
|
-
context 'with field value exceeding custom limit' do
|
40
|
-
subject { model.new(name: '*' * 140) }
|
41
|
-
it { should_not be_valid }
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'with field value not exceeding custom limit' do
|
45
|
-
subject { model.new(name: '*' * 120) }
|
46
|
-
it { should be_valid }
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'for `text` columns' do
|
52
|
-
context 'with field with default limit' do
|
53
|
-
before do
|
54
|
-
run_migration do
|
55
|
-
create_table(:users, force: true) { |t| t.text :bio }
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'with field value exceeding limit' do
|
60
|
-
subject { model.new(bio: '*' * 70000) }
|
61
|
-
it { should_not be_valid }
|
62
|
-
end
|
63
|
-
|
64
|
-
context 'with field value not exceeding limit' do
|
65
|
-
subject { model.new(bio: '*' * 4000) }
|
66
|
-
it { should be_valid }
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'with field with custom limit' do
|
71
|
-
before do
|
72
|
-
run_migration do
|
73
|
-
create_table(:users, force: true) { |t| t.text :bio, limit: 10000 }
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context 'with field value exceeding default limit' do
|
78
|
-
subject { model.new(bio: '*' * 70000) }
|
79
|
-
it { should_not be_valid }
|
80
|
-
end
|
81
|
-
|
82
|
-
context 'with field value exceeding custom limit' do
|
83
|
-
subject { model.new(bio: '*' * 12000) }
|
84
|
-
it { should_not be_valid }
|
85
|
-
end
|
86
|
-
|
87
|
-
context 'with field value not exceeding custom limit' do
|
88
|
-
subject { model.new(bio: '*' * 4000) }
|
89
|
-
it { should be_valid }
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
context 'for `integer` columns' do
|
95
|
-
context 'with field with default limit' do
|
96
|
-
before do
|
97
|
-
run_migration do
|
98
|
-
create_table(:users, force: true) { |t| t.integer :number }
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
context 'with field value exceeding limit' do
|
103
|
-
subject { model.new(number: 9999999999) }
|
104
|
-
it { should_not be_valid }
|
105
|
-
end
|
106
|
-
|
107
|
-
context 'with field value not exceeding limit' do
|
108
|
-
subject { model.new(number: 2147483647) }
|
109
|
-
it { should be_valid }
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
context 'for model with related validations' do
|
116
|
-
context 'for presence validation' do
|
117
|
-
let(:model) do
|
118
|
-
strict_model('User') { validates :name, presence: true }
|
119
|
-
end
|
120
|
-
|
121
|
-
before do
|
122
|
-
run_migration do
|
123
|
-
create_table(:users, force: true) { |t| t.string :name }
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
subject { model.new.tap(&:valid?) }
|
128
|
-
it { expect(subject.errors.full_messages).to eql ["Name can't be blank"] }
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
context 'for valid model with accessor that returns an invalid string' do
|
133
|
-
let(:model) do
|
134
|
-
strict_model 'User' do
|
135
|
-
attr_reader :long_name
|
136
|
-
|
137
|
-
# When we call `#long_name` it will return an invalid string but
|
138
|
-
# we want the attribute to store the real, valid value because we
|
139
|
-
# want to actually make sure that the real attribute value does
|
140
|
-
# not exceed the limit, not what the accessor returns.
|
141
|
-
define_method :long_name= do |value|
|
142
|
-
@long_name = '*' * 400
|
143
|
-
write_attribute(:long_name, value)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
before do
|
149
|
-
run_migration do
|
150
|
-
create_table(:users, force: true) { |t| t.string :long_name }
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
subject { model.new(long_name: '*' * 10) }
|
155
|
-
its(:long_name) { should eql '*' * 400 }
|
156
|
-
it { should be_valid }
|
157
|
-
end
|
158
|
-
|
159
|
-
context 'for invalid model with accessor that returns a valid string' do
|
160
|
-
let(:model) do
|
161
|
-
strict_model 'User' do
|
162
|
-
attr_reader :short_name
|
163
|
-
|
164
|
-
# When we call `#short_name` it will return a valid string but
|
165
|
-
# we want the attribute to store the real, valid value because we
|
166
|
-
# want to actually make sure that the real attribute value does
|
167
|
-
# exceed the limit, not what the accessor returns.
|
168
|
-
define_method :short_name= do |value|
|
169
|
-
@short_name = '*' * 100
|
170
|
-
write_attribute(:short_name, value)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
before do
|
176
|
-
run_migration do
|
177
|
-
create_table(:users, force: true) { |t| t.string :short_name }
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
subject { model.new(short_name: '*' * 400) }
|
182
|
-
its(:short_name) { should eql '*' * 100 }
|
183
|
-
it { should_not be_valid }
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|