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 ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.0.0
5
+ - 1.9.3
6
+
7
+ gemfile:
8
+ - gemfiles/Gemfile.activerecord-4.0
9
+ - gemfiles/Gemfile.activerecord-3.2.x
10
+
11
+ script: "echo 'DO IT' && bundle exec rake spec"
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'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ gem 'activerecord', '~> 3.2.0'
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '../'
4
+
5
+ gem 'activerecord', '~> 4.0.0'
@@ -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.select { |c| c.type == :string }.each do |field|
21
- validates field.name, length: { in: 0..(field.limit || 255) }, allow_blank: true
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
- model_columns.select { |c| c.type == :text }.each do |field|
25
- validates field.name, length: { in: 0..(field.limit || 65535) }, allow_blank: true
26
- end
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
- model_columns.select { |c| c.type == :integer }.each do |field|
29
- validates field.name, numericality: { greather_than_or_equal_to: -2147483647, less_than_or_equal_to: 2147483647 }, allow_blank: true
30
- end
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,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module MySQL
3
3
  module Strict
4
- VERSION = '0.1'
4
+ VERSION = '0.1.1'
5
5
  end
6
6
  end
7
7
  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 'User' do
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: '0.1'
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-05 00:00:00.000000000 Z
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: -412845040514754438
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: -412845040514754438
175
+ hash: -369873074256560002
156
176
  requirements: []
157
177
  rubyforge_project:
158
178
  rubygems_version: 1.8.23