rescue_unique_constraint 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0e3cb076ff7875dceb8444be36ef82080bcd05c
4
+ data.tar.gz: 353306cab3df3aa689c7c74f4208c30d28c05c91
5
+ SHA512:
6
+ metadata.gz: 230a6f59b281782ace42043b97ccee346739b4db72bc42091a24017636491af825bbc1f2cc9aac05a2928193b69ae8dbe674c25598b9a84037ede76e4f1b206d
7
+ data.tar.gz: e6326eb248afb2684f3a58f9246c56152a58478a497fda051fc491a948afde9fa4b46d38ae149610cd733636b3e0de39c7e59b26403bc5e5f7a6f5ae23c245d0
data/.gitignore ADDED
@@ -0,0 +1,22 @@
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
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rescue_unique_constraint.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2015 Reverb.com, LLC
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # RescueUniqueConstraint
2
+
3
+ Rails doesn't do a great job of rescuing ActiveRecord::RecordNotUnique
4
+ violations resulting from a duplicate entry on a unique constraint.
5
+
6
+ This gem automatically rescues the error and instead adds a validation error
7
+ on the field in question, making it behave as if you had a normal uniqueness
8
+ validation.
9
+
10
+ Note that if you have only a unique constraint and no uniquness validation, it
11
+ is possible for your object to validate but then fail to save.
12
+
13
+ See Usage for more info.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ gem 'rescue_unique_constraint'
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install rescue_unique_constraint
28
+
29
+ ## Usage
30
+
31
+ Assuming you've added unique index:
32
+
33
+ class AddIndexToThing < ActiveRecord::Migration
34
+ disable_ddl_transaction!
35
+
36
+ def change
37
+ add_index :things, :somefield, unique: true, algorithm: :concurrently, name: "my_unique_index"
38
+ end
39
+ end
40
+
41
+ Before:
42
+
43
+ class Thing < ActiveRecord::Base
44
+ end
45
+
46
+ thing = Thing.create(somefield: "foo")
47
+ dupe = Thing.create(somefield: "foo")
48
+ => raises ActiveRecord::RecordNotUnique
49
+
50
+ Note that if you have `validates :uniqueness` in your model, it will prevent
51
+ the RecordNotUnique from being raised in _some_ cases, but not all, as race
52
+ conditions between multiple processes will still cause duplicate entries to
53
+ enter your database.
54
+
55
+ After:
56
+
57
+ class Thing < ActiveRecord::Base
58
+ rescue_unique_constraint index: "my_unique_index", field: "somefield"
59
+ end
60
+
61
+ thing = Thing.create(somefield: "foo")
62
+ dupe = Thing.create(somefield: "foo")
63
+ => false
64
+ thing.errors[:somefield] == "somefield has already been taken"
65
+ => true
66
+
67
+ ## Testing
68
+
69
+ You'll need a database that supports unique constraints.
70
+ This gem has been tested with PostgreSQL and SQLite only.
71
+
72
+ ## Contributing
73
+
74
+ 1. Fork it ( https://github.com/[my-github-username]/rescue_unique_constraint/fork )
75
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
76
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
77
+ 4. Push to the branch (`git push origin my-new-feature`)
78
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,34 @@
1
+ require "rescue_unique_constraint/version"
2
+ require 'active_record'
3
+
4
+ module RescueUniqueConstraint
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def rescue_unique_constraint(index:, field:)
11
+ define_method(:create_or_update_with_rescue) do
12
+ begin
13
+ create_or_update_without_rescue
14
+ rescue ActiveRecord::RecordNotUnique => e
15
+ case e.message
16
+ when /#{index}/ # Postgres
17
+ errors.add(field, :taken)
18
+ when /UNIQUE.*#{field}/ # SQLite
19
+ errors.add(field, :taken)
20
+ else
21
+ # This should not happen; we want to know if we forgot to handle some unique constraint
22
+ raise e
23
+ end
24
+ false
25
+ end
26
+ end
27
+
28
+ alias_method :create_or_update_without_rescue, :create_or_update
29
+ alias_method :create_or_update, :create_or_update_with_rescue
30
+ end
31
+ end
32
+ end
33
+
34
+ ActiveRecord::Base.include(RescueUniqueConstraint)
@@ -0,0 +1,3 @@
1
+ module RescueUniqueConstraint
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rescue_unique_constraint/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rescue_unique_constraint"
8
+ spec.version = RescueUniqueConstraint::VERSION
9
+ spec.authors = ["Tam Dang", "Yan Pritzker"]
10
+ spec.email = ["tam.dang@reverb.com","yan@reverb.com"]
11
+ spec.summary = %q{Turns ActiveRecord::RecordNotUnique errors into ActiveRecord errors}
12
+ spec.description = %q{Rescues unique constraint violations and turns them into ActiveRecord errors}
13
+ spec.homepage = "https://github.com/reverbdotcom/rescue_unique_contraint"
14
+ spec.license = "Apache 2.0"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activerecord", "~> 4.1"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake", "~> 10.5"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "sqlite3", "~> 1.3"
27
+ end
@@ -0,0 +1,27 @@
1
+ require 'active_record'
2
+ require 'rescue_unique_constraint'
3
+
4
+ describe RescueUniqueConstraint do
5
+ before do
6
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
7
+ ActiveRecord::Schema.verbose = false
8
+ ActiveRecord::Schema.define(:version => 1) do
9
+ create_table :things do |t|
10
+ t.string :name
11
+ end
12
+
13
+ add_index :things, :name, unique: true, name: "idx_things_on_name_unique"
14
+ end
15
+ end
16
+
17
+ class Thing < ActiveRecord::Base
18
+ rescue_unique_constraint index: "idx_things_on_name_unique", field: "name"
19
+ end
20
+
21
+ it "rescues unique constraint violations as activerecord errors" do
22
+ thing = Thing.create(name: "foo")
23
+ dupe = Thing.new(name: "foo")
24
+ expect(dupe.save).to eql false
25
+ expect(dupe.errors[:name].first).to match /taken/
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rescue_unique_constraint
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tam Dang
8
+ - Yan Pritzker
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-01-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '4.1'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '4.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.6'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.6'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '10.5'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '10.5'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '3.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: sqlite3
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.3'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '1.3'
84
+ description: Rescues unique constraint violations and turns them into ActiveRecord
85
+ errors
86
+ email:
87
+ - tam.dang@reverb.com
88
+ - yan@reverb.com
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - ".gitignore"
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - lib/rescue_unique_constraint.rb
99
+ - lib/rescue_unique_constraint/version.rb
100
+ - rescue_unique_constraint.gemspec
101
+ - spec/rescue_unique_constraint_spec.rb
102
+ homepage: https://github.com/reverbdotcom/rescue_unique_contraint
103
+ licenses:
104
+ - Apache 2.0
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.4.8
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: Turns ActiveRecord::RecordNotUnique errors into ActiveRecord errors
126
+ test_files:
127
+ - spec/rescue_unique_constraint_spec.rb