activerecord_mysql_strict 0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +11 -0
- data/README.md +12 -0
- data/activerecord_mysql_strict.gemspec +1 -0
- data/gemfiles/Gemfile.activerecord-3.2.x +5 -0
- data/gemfiles/Gemfile.activerecord-4.0 +5 -0
- data/lib/active_record/mysql/strict/mixin.rb +18 -8
- data/lib/active_record/mysql/strict/strict_length_validator.rb +28 -0
- data/lib/active_record/mysql/strict/version.rb +1 -1
- data/lib/activerecord_mysql_strict.rb +2 -0
- data/spec/activerecord_mysql_strict/mixin_spec.rb +27 -3
- metadata +24 -4
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# ActiveRecord::MySQL::Strict
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/activerecord_mysql_strict.png)](https://rubygems.org/gems/activerecord_mysql_strict)
|
4
|
+
[![Build Status](https://travis-ci.org/mirego/activerecord_mysql_strict.png?branch=master)](https://travis-ci.org/mirego/activerecord_mysql_strict)
|
4
5
|
|
5
6
|
`ActiveRecord::MySQL::Strict` adds validations to ActiveRecord models to make sure they do not trigger errors in MySQL strict mode.
|
6
7
|
|
@@ -17,6 +18,7 @@ gem 'activerecord_mysql_strict'
|
|
17
18
|
```ruby
|
18
19
|
create_table "events" do |t|
|
19
20
|
t.string "name"
|
21
|
+
t.string "email", limit: 128
|
20
22
|
t.text "description"
|
21
23
|
t.integer "people_count"
|
22
24
|
end
|
@@ -33,6 +35,12 @@ event.valid? # => false
|
|
33
35
|
event = Event.new(name: '.' * 255)
|
34
36
|
event.valid? # => true
|
35
37
|
|
38
|
+
event = Event.new(email: '.' * 200)
|
39
|
+
event.valid? # => false
|
40
|
+
|
41
|
+
event = Event.new(email: '.' * 100)
|
42
|
+
event.valid? # => true
|
43
|
+
|
36
44
|
# Text columns
|
37
45
|
|
38
46
|
event = Event.new(description: '.' * 70000)
|
@@ -64,6 +72,10 @@ class Event < ActiveRecord::Base
|
|
64
72
|
end
|
65
73
|
```
|
66
74
|
|
75
|
+
## Todo
|
76
|
+
|
77
|
+
* Support other MySQL column types that raise a `Mysql2::Error` exception when given a wrong value.
|
78
|
+
|
67
79
|
## License
|
68
80
|
|
69
81
|
`ActiveRecord::MySQL::Strict` is © 2013 [Mirego](http://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/activerecord_mysql_strict/blob/master/LICENSE.md) file.
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency 'activerecord', '>= 3.0.0'
|
22
|
+
spec.add_dependency 'activemodel', '>= 3.0.0'
|
22
23
|
spec.add_dependency 'activesupport', '>= 3.0.0'
|
23
24
|
|
24
25
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module MySQL
|
3
3
|
module Strict
|
4
|
+
# Constants
|
5
|
+
MYSQL_STRICT_STRING_LIMIT = 255
|
6
|
+
MYSQL_STRICT_TEXT_LIMIT = 65535
|
7
|
+
MYSQL_STRICT_INTEGER_LIMIT = 2147483647
|
8
|
+
|
4
9
|
module Mixin
|
5
10
|
extend ActiveSupport::Concern
|
6
11
|
|
@@ -17,17 +22,22 @@ module ActiveRecord
|
|
17
22
|
model_columns = model_columns.select { |c| only.include?(c.name.to_sym) }
|
18
23
|
end
|
19
24
|
|
20
|
-
model_columns.
|
21
|
-
|
25
|
+
model_columns.each do |field|
|
26
|
+
method = :"define_mysql_strict_#{field.type}_validation"
|
27
|
+
send(method, field) if respond_to?(method)
|
22
28
|
end
|
29
|
+
end
|
23
30
|
|
24
|
-
|
25
|
-
|
26
|
-
|
31
|
+
def define_mysql_strict_string_validation(field)
|
32
|
+
validates field.name, 'ActiveRecord::MySQL::Strict::StrictLength' => { in: 0..(field.limit || MYSQL_STRICT_STRING_LIMIT) }, allow_blank: true
|
33
|
+
end
|
27
34
|
|
28
|
-
|
29
|
-
|
30
|
-
|
35
|
+
def define_mysql_strict_text_validation(field)
|
36
|
+
validates field.name, 'ActiveRecord::MySQL::Strict::StrictLength' => { in: 0..(field.limit || MYSQL_STRICT_TEXT_LIMIT) }, allow_blank: true
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_mysql_strict_integer_validation(field)
|
40
|
+
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
|
31
41
|
end
|
32
42
|
end
|
33
43
|
end
|
@@ -0,0 +1,28 @@
|
|
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,8 +1,10 @@
|
|
1
1
|
require 'active_record/mysql/strict/version'
|
2
2
|
|
3
3
|
require 'active_record'
|
4
|
+
require 'active_model'
|
4
5
|
require 'active_support'
|
5
6
|
|
7
|
+
require 'active_record/mysql/strict/strict_length_validator'
|
6
8
|
require 'active_record/mysql/strict/mixin'
|
7
9
|
|
8
10
|
class ActiveRecord::Base
|
@@ -115,9 +115,7 @@ describe ActiveRecord::MySQL::Strict::Mixin do
|
|
115
115
|
context 'for model with related validations' do
|
116
116
|
context 'for presence validation' do
|
117
117
|
let(:model) do
|
118
|
-
strict_model
|
119
|
-
validates :name, presence: true
|
120
|
-
end
|
118
|
+
strict_model('User') { validates :name, presence: true }
|
121
119
|
end
|
122
120
|
|
123
121
|
before do
|
@@ -130,5 +128,31 @@ describe ActiveRecord::MySQL::Strict::Mixin do
|
|
130
128
|
it { expect(subject.errors.full_messages).to eql ["Name can't be blank"] }
|
131
129
|
end
|
132
130
|
end
|
131
|
+
|
132
|
+
context 'for 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
|
+
it { should be_valid }
|
156
|
+
end
|
133
157
|
end
|
134
158
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord_mysql_strict
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activemodel
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.0.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.0.0
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: activesupport
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -117,11 +133,15 @@ extra_rdoc_files: []
|
|
117
133
|
files:
|
118
134
|
- .gitignore
|
119
135
|
- .rspec
|
136
|
+
- .travis.yml
|
120
137
|
- Gemfile
|
121
138
|
- README.md
|
122
139
|
- Rakefile
|
123
140
|
- activerecord_mysql_strict.gemspec
|
141
|
+
- gemfiles/Gemfile.activerecord-3.2.x
|
142
|
+
- gemfiles/Gemfile.activerecord-4.0
|
124
143
|
- lib/active_record/mysql/strict/mixin.rb
|
144
|
+
- lib/active_record/mysql/strict/strict_length_validator.rb
|
125
145
|
- lib/active_record/mysql/strict/version.rb
|
126
146
|
- lib/activerecord_mysql_strict.rb
|
127
147
|
- spec/activerecord_mysql_strict/mixin_spec.rb
|
@@ -143,7 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
143
163
|
version: '0'
|
144
164
|
segments:
|
145
165
|
- 0
|
146
|
-
hash: -
|
166
|
+
hash: -369873074256560002
|
147
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
168
|
none: false
|
149
169
|
requirements:
|
@@ -152,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
172
|
version: '0'
|
153
173
|
segments:
|
154
174
|
- 0
|
155
|
-
hash: -
|
175
|
+
hash: -369873074256560002
|
156
176
|
requirements: []
|
157
177
|
rubyforge_project:
|
158
178
|
rubygems_version: 1.8.23
|