activerecord_mysql_strict 0.1 → 0.1.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.
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