cerbero 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p194
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ 1.8.7
4
+ 1.9.3
5
+ env:
6
+ - DB=sqlite
7
+ - DB=mysql
8
+ - DB=postgres
9
+ notifications:
10
+ email:
11
+ - dmitriy.kiriyenko@gmail.com
data/Appraisals ADDED
@@ -0,0 +1,11 @@
1
+ appraise "activerecord30" do
2
+ gem "activerecord", "~> 3.0.15"
3
+ end
4
+
5
+ appraise "activerecord31" do
6
+ gem "activerecord", "~> 3.1.6"
7
+ end
8
+
9
+ appraise "activerecord32" do
10
+ gem "activerecord", "~> 3.2.6"
11
+ end
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cerbero.gemspec
4
+ gemspec
5
+
6
+ gem 'appraisal'
7
+ group :db do
8
+ gem 'mysql2'
9
+ gem 'pg'
10
+ end
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Dmitriy Kiriyenko
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Cerbero
2
+
3
+ Uniqueness validation do not guarantee uniqueness. Only the database
4
+ constraints do this. But there is a flaw - when database constraints
5
+ fail, an exception is thrown, and even when we catch it, the validation
6
+ error is not set.
7
+
8
+ This gem solves the issue.
9
+
10
+ It catches the database constraints exception, revalidates and returns
11
+ `false` from save. To use it, you should set _both_ validation and
12
+ database constraint. Then even if uniqueness validation mistakenly let
13
+ you in, it will break the database constraint, then revalidate and the
14
+ validation will tell you the truth.
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'cerbero'
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ Say you need the uniqueness of `email` inside the `company_id`. In your
27
+ model you should say:
28
+
29
+ ```ruby
30
+ validates :email, uniqueness: {scope: :company_id}
31
+ ```
32
+
33
+ and in your migration:
34
+
35
+ ```ruby
36
+ add_index :users, [:email, :company_id], unique: true
37
+ ```
38
+
39
+ Then if the gem is required, it makes the stuff work so that when the
40
+ uniqueness validtion lets you in, but the database constraint then
41
+ fails, `save` returns `false`, then uniqueness validation is re-run and
42
+ the execution flow goes like the uniqueness validation worked perfectly.
43
+
44
+
45
+ ## Contributing
46
+
47
+ Use it! Provide me the issues if found. If you are really willing to
48
+ provide some code:
49
+
50
+ 1. Fork it
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
52
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
53
+ 4. Push to the branch (`git push origin my-new-feature`)
54
+ 5. Create new Pull Request
55
+
56
+ ## TODO:
57
+
58
+ - Apply a cleaner pattern to test via multiple databases.
59
+ - Add travis-ci - it's broken for some reason.
60
+ - Extract the save monkey-patch to module and apply the
61
+ `alias_method_chain` pattern to avoid possible collisions.
62
+ - Add an option to apply the gem per-model basis.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+
6
+ require 'appraisal'
7
+ require 'bundler/gem_tasks'
8
+ require 'rspec/core/rake_task'
9
+
10
+ task :default => ["appraisal:install"] do
11
+ exec('rake appraisal spec')
12
+ end
13
+
14
+ RSpec::Core::RakeTask.new(:spec) do |t|
15
+ end
data/cerbero.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/cerbero/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Dmitriy Kiriyenko"]
6
+ gem.email = ["dmitriy.kiriyenko@anahoret.com"]
7
+ gem.description = %q{Get validation error from database constraint.}
8
+ gem.summary = %q{Get validation error from database constraint.
9
+ You can be sure your uniqueness validation guarantees uniqueness.}
10
+ gem.homepage = ""
11
+
12
+ gem.add_dependency "activerecord", ">= 3.0.0"
13
+ gem.add_development_dependency "rspec", ">= 2.0.0"
14
+ gem.add_development_dependency "rake"
15
+ gem.add_development_dependency "database_cleaner"
16
+ gem.add_development_dependency "sqlite3"
17
+
18
+ gem.files = `git ls-files`.split($\)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.name = "cerbero"
22
+ gem.require_paths = ["lib"]
23
+ gem.version = Cerbero::VERSION
24
+ end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "activerecord", "~> 3.0.15"
7
+
8
+ gemspec :path=>"../"
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: /Users/dak/projects/cerbero
3
+ specs:
4
+ cerbero (0.0.1)
5
+ activerecord (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (3.0.15)
11
+ activesupport (= 3.0.15)
12
+ builder (~> 2.1.2)
13
+ i18n (~> 0.5.0)
14
+ activerecord (3.0.15)
15
+ activemodel (= 3.0.15)
16
+ activesupport (= 3.0.15)
17
+ arel (~> 2.0.10)
18
+ tzinfo (~> 0.3.23)
19
+ activesupport (3.0.15)
20
+ appraisal (0.4.1)
21
+ bundler
22
+ rake
23
+ arel (2.0.10)
24
+ builder (2.1.2)
25
+ database_cleaner (0.8.0)
26
+ diff-lcs (1.1.3)
27
+ i18n (0.5.0)
28
+ rake (0.9.2.2)
29
+ rspec (2.11.0)
30
+ rspec-core (~> 2.11.0)
31
+ rspec-expectations (~> 2.11.0)
32
+ rspec-mocks (~> 2.11.0)
33
+ rspec-core (2.11.0)
34
+ rspec-expectations (2.11.1)
35
+ diff-lcs (~> 1.1.3)
36
+ rspec-mocks (2.11.0)
37
+ sqlite3 (1.3.6)
38
+ tzinfo (0.3.33)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ activerecord (~> 3.0.15)
45
+ appraisal
46
+ cerbero!
47
+ database_cleaner
48
+ rake
49
+ rspec (>= 2.0.0)
50
+ sqlite3
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "activerecord", "~> 3.1.6"
7
+
8
+ gemspec :path=>"../"
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: /Users/dak/projects/cerbero
3
+ specs:
4
+ cerbero (0.0.1)
5
+ activerecord (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (3.1.6)
11
+ activesupport (= 3.1.6)
12
+ builder (~> 3.0.0)
13
+ i18n (~> 0.6)
14
+ activerecord (3.1.6)
15
+ activemodel (= 3.1.6)
16
+ activesupport (= 3.1.6)
17
+ arel (~> 2.2.3)
18
+ tzinfo (~> 0.3.29)
19
+ activesupport (3.1.6)
20
+ multi_json (>= 1.0, < 1.3)
21
+ appraisal (0.4.1)
22
+ bundler
23
+ rake
24
+ arel (2.2.3)
25
+ builder (3.0.0)
26
+ database_cleaner (0.8.0)
27
+ diff-lcs (1.1.3)
28
+ i18n (0.6.0)
29
+ multi_json (1.2.0)
30
+ rake (0.9.2.2)
31
+ rspec (2.11.0)
32
+ rspec-core (~> 2.11.0)
33
+ rspec-expectations (~> 2.11.0)
34
+ rspec-mocks (~> 2.11.0)
35
+ rspec-core (2.11.0)
36
+ rspec-expectations (2.11.1)
37
+ diff-lcs (~> 1.1.3)
38
+ rspec-mocks (2.11.0)
39
+ sqlite3 (1.3.6)
40
+ tzinfo (0.3.33)
41
+
42
+ PLATFORMS
43
+ ruby
44
+
45
+ DEPENDENCIES
46
+ activerecord (~> 3.1.6)
47
+ appraisal
48
+ cerbero!
49
+ database_cleaner
50
+ rake
51
+ rspec (>= 2.0.0)
52
+ sqlite3
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "activerecord", "~> 3.2.6"
7
+
8
+ gemspec :path=>"../"
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: /Users/dak/projects/cerbero
3
+ specs:
4
+ cerbero (0.0.1)
5
+ activerecord (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (3.2.6)
11
+ activesupport (= 3.2.6)
12
+ builder (~> 3.0.0)
13
+ activerecord (3.2.6)
14
+ activemodel (= 3.2.6)
15
+ activesupport (= 3.2.6)
16
+ arel (~> 3.0.2)
17
+ tzinfo (~> 0.3.29)
18
+ activesupport (3.2.6)
19
+ i18n (~> 0.6)
20
+ multi_json (~> 1.0)
21
+ appraisal (0.4.1)
22
+ bundler
23
+ rake
24
+ arel (3.0.2)
25
+ builder (3.0.0)
26
+ database_cleaner (0.8.0)
27
+ diff-lcs (1.1.3)
28
+ i18n (0.6.0)
29
+ multi_json (1.3.6)
30
+ rake (0.9.2.2)
31
+ rspec (2.11.0)
32
+ rspec-core (~> 2.11.0)
33
+ rspec-expectations (~> 2.11.0)
34
+ rspec-mocks (~> 2.11.0)
35
+ rspec-core (2.11.0)
36
+ rspec-expectations (2.11.1)
37
+ diff-lcs (~> 1.1.3)
38
+ rspec-mocks (2.11.0)
39
+ sqlite3 (1.3.6)
40
+ tzinfo (0.3.33)
41
+
42
+ PLATFORMS
43
+ ruby
44
+
45
+ DEPENDENCIES
46
+ activerecord (~> 3.2.6)
47
+ appraisal
48
+ cerbero!
49
+ database_cleaner
50
+ rake
51
+ rspec (>= 2.0.0)
52
+ sqlite3
@@ -0,0 +1,3 @@
1
+ module Cerbero
2
+ VERSION = "0.0.1"
3
+ end
data/lib/cerbero.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "cerbero/version"
2
+
3
+ class ActiveRecord::Base
4
+ def save
5
+ super
6
+ rescue ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid
7
+ valid?
8
+ false
9
+ end
10
+ end
11
+
12
+ module Cerbero
13
+ # Your code goes here...
14
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'cerbero'
3
+
4
+ describe 'cerbero' do
5
+ def stub_uniqueness_validation!
6
+ ActiveRecord::Relation.any_instance.stub(:exists?) {
7
+ ActiveRecord::Relation.any_instance.unstub :exists?
8
+ false
9
+ }
10
+ end
11
+
12
+ it 'gives validation error when database constraint throws error' do
13
+ User.create! :email => 'test@mailinator.com', :company_id => 25
14
+
15
+ stub_uniqueness_validation!
16
+ user = User.create :email => 'test@mailinator.com', :company_id => 25
17
+
18
+ user.errors[:email].should_not be_blank
19
+ end
20
+
21
+ it 'gives validation error when database constraint throws error' do
22
+ User.create! :email => 'test@mailinator.com', :company_id => 25
23
+
24
+ stub_uniqueness_validation!
25
+ Proc.new {
26
+ UserWithSaveError.create :email => 'test@mailinator.com', :company_id => 25
27
+ }.should raise_error(RuntimeError)
28
+ end
29
+ end
data/spec/database.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'active_record'
2
+ Bundler.require 'db'
3
+
4
+ test_conf = case ENV['DB']
5
+ when 'mysql'
6
+ system "mysql -uroot -e 'drop database cerbero_test; create database cerbero_test;'"
7
+ {:adapter => 'mysql2', :database => 'cerbero_test', :username => 'root', :encoding => 'utf8'}
8
+ when 'postgres'
9
+ system "`psql -c 'drop database cerbero_test;' -U postgres`"
10
+ system "`psql -c 'create database cerbero_test;' -U postgres`"
11
+ {:adapter => 'postgresql', :database => 'cerbero_test', :username => 'postgres'}
12
+ else
13
+ {:adapter => 'sqlite3', :database => ':memory:', :timeout => 500}
14
+ end
15
+
16
+ ActiveRecord::Base.configurations = {'test' => test_conf}
17
+ ActiveRecord::Base.establish_connection('test')
18
+
19
+ ActiveRecord::Migration.verbose = false unless ENV.has_key?('DEBUG')
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'database_cleaner'
4
+
5
+ # Establishes database connection
6
+ require File.join(File.dirname(__FILE__), 'database')
7
+
8
+ # Requires supporting files with custom matchers and macros, etc,
9
+ # in ./support/ and its subdirectories.
10
+ Dir[File.join(File.dirname(__FILE__), "support", "**", "*.rb")].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ config.before(:each) do
14
+ DatabaseCleaner.clean_with :truncation
15
+ end
16
+ end
File without changes
@@ -0,0 +1,19 @@
1
+ class User < ActiveRecord::Base
2
+ validates :email, :uniqueness => {:scope => :company_id}
3
+ end
4
+
5
+ class UserWithSaveError < ActiveRecord::Base
6
+ self.table_name = 'users'
7
+
8
+ validates :email, :uniqueness => {:scope => :company_id}
9
+ before_save { raise RuntimeError }
10
+ end
11
+
12
+ ActiveRecord::Schema.define(:version => 1) do
13
+ create_table :users do |t|
14
+ t.string :email
15
+ t.integer :company_id
16
+ end
17
+
18
+ add_index :users, [:email, :company_id], :unique => true
19
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cerbero
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dmitriy Kiriyenko
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 2.0.0
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 2.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: database_cleaner
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: sqlite3
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: Get validation error from database constraint.
95
+ email:
96
+ - dmitriy.kiriyenko@anahoret.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - .rbenv-version
103
+ - .rspec
104
+ - .travis.yml
105
+ - Appraisals
106
+ - Gemfile
107
+ - MIT-LICENSE
108
+ - README.md
109
+ - Rakefile
110
+ - cerbero.gemspec
111
+ - gemfiles/activerecord30.gemfile
112
+ - gemfiles/activerecord30.gemfile.lock
113
+ - gemfiles/activerecord31.gemfile
114
+ - gemfiles/activerecord31.gemfile.lock
115
+ - gemfiles/activerecord32.gemfile
116
+ - gemfiles/activerecord32.gemfile.lock
117
+ - lib/cerbero.rb
118
+ - lib/cerbero/version.rb
119
+ - spec/cerbero_spec.rb
120
+ - spec/database.rb
121
+ - spec/spec_helper.rb
122
+ - spec/support/.gitkeep
123
+ - spec/support/models.rb
124
+ homepage: ''
125
+ licenses: []
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ segments:
137
+ - 0
138
+ hash: -2835968287369647992
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ! '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ segments:
146
+ - 0
147
+ hash: -2835968287369647992
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 1.8.23
151
+ signing_key:
152
+ specification_version: 3
153
+ summary: Get validation error from database constraint. You can be sure your uniqueness
154
+ validation guarantees uniqueness.
155
+ test_files:
156
+ - spec/cerbero_spec.rb
157
+ - spec/database.rb
158
+ - spec/spec_helper.rb
159
+ - spec/support/.gitkeep
160
+ - spec/support/models.rb