rescue_unique_constraint 1.0.0 → 1.1.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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +2 -0
- data/README.md +4 -3
- data/lib/rescue_unique_constraint/adapter/postgresql_adapter.rb +9 -0
- data/lib/rescue_unique_constraint/adapter/sqlite_adapter.rb +9 -0
- data/lib/rescue_unique_constraint/index.rb +9 -0
- data/lib/rescue_unique_constraint/rescue_handler.rb +42 -0
- data/lib/rescue_unique_constraint/version.rb +1 -1
- data/lib/rescue_unique_constraint.rb +27 -19
- data/rescue_unique_constraint.gemspec +2 -0
- data/spec/rescue_unique_constraint_spec.rb +7 -2
- metadata +37 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27efaf5971c6a6112e6bd8a425dce94b75c460be
|
4
|
+
data.tar.gz: 9ad629f199f45389fcc44e86ba4dd7a563d5393a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3889a2162aa6549ede31230f0d2d6fbda77a81ed59b59fcd1b220c0ecf17b682bdb850ac1a521fde94e17bc8b5e57f4fe0f16b437766983abe0b6497d52959e
|
7
|
+
data.tar.gz: 4bacd362cc9b17643ca4d181753b4cb666759b69e54dc9b82a6bb2110e10efa5bf7a593065071509e8902c2cedd43013f8be49cd9182e500dbcbd88fdc58b1b2
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# RescueUniqueConstraint
|
2
2
|
|
3
|
-
|
4
|
-
violations resulting from a duplicate entry on a unique constraint.
|
3
|
+
ActiveRecord doesn't do a great job of rescuing ActiveRecord::RecordNotUnique
|
4
|
+
violations resulting from a duplicate entry on a database level unique constraint.
|
5
5
|
|
6
6
|
This gem automatically rescues the error and instead adds a validation error
|
7
7
|
on the field in question, making it behave as if you had a normal uniqueness
|
8
8
|
validation.
|
9
9
|
|
10
|
-
Note that if you have only a unique constraint and no
|
10
|
+
Note that if you have only a unique constraint in the database and no uniqueness validation in ActiveRecord, it
|
11
11
|
is possible for your object to validate but then fail to save.
|
12
12
|
|
13
13
|
See Usage for more info.
|
@@ -55,6 +55,7 @@ enter your database.
|
|
55
55
|
After:
|
56
56
|
|
57
57
|
class Thing < ActiveRecord::Base
|
58
|
+
include RescueUniqueConstraint
|
58
59
|
rescue_unique_constraint index: "my_unique_index", field: "somefield"
|
59
60
|
end
|
60
61
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module RescueUniqueConstraint
|
2
|
+
# Handles storing and matching [index, field] pairs to exceptions
|
3
|
+
class RescueHandler
|
4
|
+
def initialize(model)
|
5
|
+
@model = model
|
6
|
+
@indexes_to_rescue_on = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_index(index, field)
|
10
|
+
indexes_to_rescue_on << Index.new(index, field)
|
11
|
+
end
|
12
|
+
|
13
|
+
def matching_indexes(e)
|
14
|
+
indexes = indexes_to_rescue_on.select do |index|
|
15
|
+
database_adapter.index_error?(index, e.message)
|
16
|
+
end
|
17
|
+
raise e unless indexes.any?
|
18
|
+
indexes
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :indexes_to_rescue_on, :model
|
24
|
+
|
25
|
+
def database_adapter
|
26
|
+
@_database_adapter ||= (
|
27
|
+
case database_name
|
28
|
+
when :postgresql
|
29
|
+
Adapter::PostgresqlAdapter.new
|
30
|
+
when :sqlite
|
31
|
+
Adapter::SqliteAdapter.new
|
32
|
+
else
|
33
|
+
raise "Database (#{database_name}) not supported"
|
34
|
+
end
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def database_name
|
39
|
+
model.connection.adapter_name.downcase.to_sym
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,34 +1,42 @@
|
|
1
|
-
require
|
1
|
+
require 'rescue_unique_constraint/version'
|
2
|
+
require 'rescue_unique_constraint/index'
|
3
|
+
require 'rescue_unique_constraint/rescue_handler'
|
4
|
+
require 'rescue_unique_constraint/adapter/postgresql_adapter'
|
5
|
+
require 'rescue_unique_constraint/adapter/sqlite_adapter'
|
2
6
|
require 'active_record'
|
3
7
|
|
8
|
+
# Module which will rescue ActiveRecord::RecordNotUnique exceptions
|
9
|
+
# and add errors for indexes that are registered with
|
10
|
+
# rescue_unique_constraint(index:, field:)
|
4
11
|
module RescueUniqueConstraint
|
5
12
|
def self.included(base)
|
6
13
|
base.extend(ClassMethods)
|
7
14
|
end
|
8
15
|
|
16
|
+
# methods mixed into ActiveRecord class
|
9
17
|
module ClassMethods
|
18
|
+
def index_rescue_handler
|
19
|
+
@_index_rescue_handler ||= RescueUniqueConstraint::RescueHandler.new(self)
|
20
|
+
end
|
21
|
+
|
10
22
|
def rescue_unique_constraint(index:, field:)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
else
|
21
|
-
# This should not happen; we want to know if we forgot to handle some unique constraint
|
22
|
-
raise e
|
23
|
+
unless method_defined?(:create_or_update_with_rescue)
|
24
|
+
define_method(:create_or_update_with_rescue) do
|
25
|
+
begin
|
26
|
+
create_or_update_without_rescue
|
27
|
+
rescue ActiveRecord::RecordNotUnique => e
|
28
|
+
self.class.index_rescue_handler.matching_indexes(e).each do |matching_index|
|
29
|
+
errors.add(matching_index.field, :taken)
|
30
|
+
end
|
31
|
+
return false
|
23
32
|
end
|
24
|
-
|
33
|
+
true
|
25
34
|
end
|
26
|
-
end
|
27
35
|
|
28
|
-
|
29
|
-
|
36
|
+
alias_method :create_or_update_without_rescue, :create_or_update
|
37
|
+
alias_method :create_or_update, :create_or_update_with_rescue
|
38
|
+
end
|
39
|
+
index_rescue_handler.add_index(index, field)
|
30
40
|
end
|
31
41
|
end
|
32
42
|
end
|
33
|
-
|
34
|
-
ActiveRecord::Base.include(RescueUniqueConstraint)
|
@@ -24,4 +24,6 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency "rake", "~> 10.5"
|
25
25
|
spec.add_development_dependency "rspec", "~> 3.0"
|
26
26
|
spec.add_development_dependency "sqlite3", "~> 1.3"
|
27
|
+
spec.add_development_dependency 'pry'
|
28
|
+
spec.add_development_dependency 'pry-byebug'
|
27
29
|
end
|
@@ -8,20 +8,25 @@ describe RescueUniqueConstraint do
|
|
8
8
|
ActiveRecord::Schema.define(:version => 1) do
|
9
9
|
create_table :things do |t|
|
10
10
|
t.string :name
|
11
|
+
t.string :test
|
11
12
|
end
|
12
13
|
|
13
14
|
add_index :things, :name, unique: true, name: "idx_things_on_name_unique"
|
15
|
+
add_index :things, :test, unique: true, name: "idx_things_on_test_unique"
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
17
19
|
class Thing < ActiveRecord::Base
|
20
|
+
include RescueUniqueConstraint
|
18
21
|
rescue_unique_constraint index: "idx_things_on_name_unique", field: "name"
|
22
|
+
rescue_unique_constraint index: "idx_things_on_test_unique", field: "test"
|
19
23
|
end
|
20
24
|
|
21
25
|
it "rescues unique constraint violations as activerecord errors" do
|
22
|
-
thing = Thing.create(name: "foo")
|
23
|
-
dupe = Thing.new(name: "foo")
|
26
|
+
thing = Thing.create(name: "foo", test: 'bar')
|
27
|
+
dupe = Thing.new(name: "foo", test: 'bar')
|
24
28
|
expect(dupe.save).to eql false
|
25
29
|
expect(dupe.errors[:name].first).to match /taken/
|
30
|
+
expect(dupe.errors[:test].first).to match /taken/
|
26
31
|
end
|
27
32
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rescue_unique_constraint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tam Dang
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2017-01-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -81,6 +81,34 @@ dependencies:
|
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '1.3'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: pry
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: pry-byebug
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
84
112
|
description: Rescues unique constraint violations and turns them into ActiveRecord
|
85
113
|
errors
|
86
114
|
email:
|
@@ -91,11 +119,16 @@ extensions: []
|
|
91
119
|
extra_rdoc_files: []
|
92
120
|
files:
|
93
121
|
- ".gitignore"
|
122
|
+
- ".rubocop.yml"
|
94
123
|
- Gemfile
|
95
124
|
- LICENSE.txt
|
96
125
|
- README.md
|
97
126
|
- Rakefile
|
98
127
|
- lib/rescue_unique_constraint.rb
|
128
|
+
- lib/rescue_unique_constraint/adapter/postgresql_adapter.rb
|
129
|
+
- lib/rescue_unique_constraint/adapter/sqlite_adapter.rb
|
130
|
+
- lib/rescue_unique_constraint/index.rb
|
131
|
+
- lib/rescue_unique_constraint/rescue_handler.rb
|
99
132
|
- lib/rescue_unique_constraint/version.rb
|
100
133
|
- rescue_unique_constraint.gemspec
|
101
134
|
- spec/rescue_unique_constraint_spec.rb
|
@@ -119,9 +152,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
152
|
version: '0'
|
120
153
|
requirements: []
|
121
154
|
rubyforge_project:
|
122
|
-
rubygems_version: 2.
|
155
|
+
rubygems_version: 2.2.2
|
123
156
|
signing_key:
|
124
157
|
specification_version: 4
|
125
158
|
summary: Turns ActiveRecord::RecordNotUnique errors into ActiveRecord errors
|
126
159
|
test_files:
|
127
160
|
- spec/rescue_unique_constraint_spec.rb
|
161
|
+
has_rdoc:
|