has_unique_attribute 0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 20a15d8b6e775b27196202f55a3620d7657649d95d3b4e82f817fc6ca56724a1
4
+ data.tar.gz: 19a566b7c92567464f326e9495b981f95bc04b99978b9913412ddf4997770545
5
+ SHA512:
6
+ metadata.gz: 48fc6ccdfd69432ecb1b7f4bd09071a697d21f5f07833e9e458f5da4b143e65ca79743b102f7c1af7127dcc9d4ede19c911aa7d2046817ce9022bf1c6d36b0f7
7
+ data.tar.gz: 17f07885a4303072c3e5517dded25e601d0ca6b9602339d99e56c5e68e87be6c5fb2cfb32acdcb221d549274434da1d4c1b55370e84acb93f968d1d39a3d2d89
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,152 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ DefaultFormatter: progress
7
+ DisplayCopNames: true
8
+ ExtraDetails: true
9
+ TargetRubyVersion: 2.6
10
+ Exclude:
11
+ - 'bin/*'
12
+
13
+ Layout/AccessModifierIndentation:
14
+ EnforcedStyle: outdent
15
+
16
+ Layout/EmptyLinesAroundAttributeAccessor:
17
+ Enabled: true
18
+
19
+ Layout/ExtraSpacing:
20
+ AllowForAlignment: true
21
+
22
+ Layout/HashAlignment:
23
+ EnforcedColonStyle: table
24
+ EnforcedHashRocketStyle: table
25
+
26
+ Layout/LineLength:
27
+ Max: 120
28
+
29
+ Layout/MultilineMethodCallIndentation:
30
+ EnforcedStyle: indented
31
+
32
+ Layout/SpaceAroundMethodCallOperator:
33
+ Enabled: true
34
+
35
+ Layout/SpaceInLambdaLiteral:
36
+ EnforcedStyle: require_space
37
+
38
+ Lint/AmbiguousBlockAssociation:
39
+ Enabled: false
40
+
41
+ Lint/DeprecatedOpenSSLConstant:
42
+ Enabled: true
43
+
44
+ Lint/DuplicateElsifCondition:
45
+ Enabled: true
46
+
47
+ Lint/MixedRegexpCaptureTypes:
48
+ Enabled: true
49
+
50
+ Lint/RaiseException:
51
+ Enabled: true
52
+
53
+ Lint/StructNewOverride:
54
+ Enabled: true
55
+
56
+ Metrics/BlockLength:
57
+ Exclude:
58
+ - 'spec/**/*'
59
+
60
+ Naming/RescuedExceptionsVariableName:
61
+ PreferredName: error
62
+
63
+ Performance/AncestorsInclude:
64
+ Enabled: true
65
+
66
+ Performance/BigDecimalWithNumericArgument:
67
+ Enabled: true
68
+
69
+ Performance/RedundantSortBlock:
70
+ Enabled: true
71
+
72
+ Performance/RedundantStringChars:
73
+ Enabled: true
74
+
75
+ Performance/ReverseFirst:
76
+ Enabled: true
77
+
78
+ Performance/SortReverse:
79
+ Enabled: true
80
+
81
+ Performance/Squeeze:
82
+ Enabled: true
83
+
84
+ Performance/StringInclude:
85
+ Enabled: true
86
+
87
+ RSpec/ExpectChange:
88
+ EnforcedStyle: block
89
+
90
+ RSpec/HookArgument:
91
+ EnforcedStyle: each
92
+
93
+ RSpec/NestedGroups:
94
+ Max: 5
95
+
96
+ Style/AccessorGrouping:
97
+ Enabled: true
98
+
99
+ Style/ArrayCoercion:
100
+ Enabled: true
101
+
102
+ Style/BisectedAttrAccessor:
103
+ Enabled: true
104
+
105
+ Style/CaseLikeIf:
106
+ Enabled: true
107
+
108
+ Style/ClassAndModuleChildren:
109
+ SafeAutoCorrect: true
110
+
111
+ Style/Documentation:
112
+ Enabled: false
113
+
114
+ Style/ExponentialNotation:
115
+ Enabled: true
116
+
117
+ Style/FrozenStringLiteralComment:
118
+ Safe: true
119
+
120
+ Style/HashAsLastArrayItem:
121
+ Enabled: true
122
+
123
+ Style/HashEachMethods:
124
+ Enabled: true
125
+
126
+ Style/HashLikeCase:
127
+ Enabled: true
128
+
129
+ Style/HashTransformKeys:
130
+ Enabled: true
131
+
132
+ Style/HashTransformValues:
133
+ Enabled: true
134
+
135
+ Style/RedundantAssignment:
136
+ Enabled: true
137
+
138
+ Style/RedundantFetchBlock:
139
+ Enabled: true
140
+ Safe: true
141
+
142
+ Style/RedundantFileExtensionInRequire:
143
+ Enabled: true
144
+
145
+ Style/RedundantRegexpCharacterClass:
146
+ Enabled: true
147
+
148
+ Style/RedundantRegexpEscape:
149
+ Enabled: true
150
+
151
+ Style/SlicingWithRange:
152
+ Enabled: true
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.5
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in has_unique_attribute.gemspec
6
+ gemspec
@@ -0,0 +1,62 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ has_unique_attribute (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.1)
10
+ diff-lcs (1.4.4)
11
+ parallel (1.19.2)
12
+ parser (2.7.1.4)
13
+ ast (~> 2.4.1)
14
+ rainbow (3.0.0)
15
+ rake (13.0.1)
16
+ regexp_parser (1.7.1)
17
+ rexml (3.2.4)
18
+ rspec (3.9.0)
19
+ rspec-core (~> 3.9.0)
20
+ rspec-expectations (~> 3.9.0)
21
+ rspec-mocks (~> 3.9.0)
22
+ rspec-core (3.9.2)
23
+ rspec-support (~> 3.9.3)
24
+ rspec-expectations (3.9.2)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.9.0)
27
+ rspec-mocks (3.9.1)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.9.0)
30
+ rspec-support (3.9.3)
31
+ rubocop (0.88.0)
32
+ parallel (~> 1.10)
33
+ parser (>= 2.7.1.1)
34
+ rainbow (>= 2.2.2, < 4.0)
35
+ regexp_parser (>= 1.7)
36
+ rexml
37
+ rubocop-ast (>= 0.1.0, < 1.0)
38
+ ruby-progressbar (~> 1.7)
39
+ unicode-display_width (>= 1.4.0, < 2.0)
40
+ rubocop-ast (0.1.0)
41
+ parser (>= 2.7.0.1)
42
+ rubocop-performance (1.7.0)
43
+ rubocop (>= 0.82.0)
44
+ rubocop-rspec (1.42.0)
45
+ rubocop (>= 0.87.0)
46
+ ruby-progressbar (1.10.1)
47
+ unicode-display_width (1.7.0)
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ bundler (~> 2.0)
54
+ has_unique_attribute!
55
+ rake (~> 13.0)
56
+ rspec (~> 3.0)
57
+ rubocop
58
+ rubocop-performance
59
+ rubocop-rspec
60
+
61
+ BUNDLED WITH
62
+ 2.0.2
@@ -0,0 +1,99 @@
1
+ # Has Unique Attribute
2
+
3
+ Applies validation errors to ActiveRecord model attributes when database uniqueness constraints fail.
4
+
5
+ **NOTE:** At the moment, only PostgreSQL is supported.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'has_unique_attribute'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install has_unique_attribute
22
+
23
+ Then, make it available to your models:
24
+
25
+ ```ruby
26
+ class ApplicationRecord < ActiveRecord::Base
27
+ extend HasUniqueAttribute
28
+
29
+ # ...
30
+ end
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ Use the `has_unique_attribute` helper to add a handler to your model:
36
+
37
+ ```ruby
38
+ class User < ApplicationRecord
39
+ has_unique_attribute :email
40
+ end
41
+ ```
42
+
43
+ This will match errors on an index name `index_users_on_email` and add validation errors to the `email` attribute.
44
+
45
+ ### Specifying an Index Name
46
+
47
+ To customize the name of the index matched, use the `index` option:
48
+
49
+ ```ruby
50
+ class User < ApplicationRecord
51
+ has_unique_attribute :email, index: 'custom_index_name'
52
+ end
53
+ ```
54
+
55
+ ### Customizing the Error Message
56
+
57
+ To customize the error message applied, use the `message` option:
58
+
59
+ ```ruby
60
+ class Project < ApplicationRecord
61
+ has_unique_attribute :name, message: 'already exists'
62
+ end
63
+ ```
64
+
65
+ It's also possible to specify an I18n key for a translation:
66
+
67
+ ```ruby
68
+ class Project < ApplicationRecord
69
+ has_unique_attribute :name, message: :duplicate
70
+ end
71
+ ```
72
+
73
+ By default, the `:taken` error translation is applied to attributes.
74
+ This mimics the behaviour of the `uniqueness` validator.
75
+
76
+ ### Handling Composite Indexes
77
+
78
+ Composite (multi-column) indexes will need the index name to be specified explicitly:
79
+
80
+ ```ruby
81
+ class Membership < Application
82
+ belongs_to :user
83
+ belongs_to :club
84
+
85
+ has_unique_index :user, index: 'index_memberships_on_club_id_and_user_id', message: 'is already a member'
86
+ end
87
+ ```
88
+
89
+ The error is only applied to the specified attribute.
90
+
91
+ ## Development
92
+
93
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
94
+
95
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
96
+
97
+ ## Contributing
98
+
99
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Mihail-K/has_unique_attribute.
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "has_unique_attribute"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rubocop", "rubocop")
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'has_unique_attribute/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'has_unique_attribute'
10
+ spec.version = HasUniqueAttribute::VERSION
11
+ spec.authors = ['Mihail-K']
12
+ spec.email = []
13
+
14
+ spec.summary = 'Handle unique attributes safely using the database.'
15
+ spec.description = 'Adds custom handling for database uniqueness constraints to ActiveRecord.'
16
+ spec.homepage = 'https://github.com/Mihail-K/has_unique_attribute'
17
+
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/Mihail-K/has_unique_attribute'
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+
27
+ spec.bindir = 'exe'
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ['lib']
30
+
31
+ spec.add_development_dependency 'bundler', '~> 2.0'
32
+ spec.add_development_dependency 'rake', '~> 13.0'
33
+ spec.add_development_dependency 'rspec', '~> 3.0'
34
+ spec.add_development_dependency 'rubocop'
35
+ spec.add_development_dependency 'rubocop-performance'
36
+ spec.add_development_dependency 'rubocop-rspec'
37
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasUniqueAttribute
4
+ # @param attribute_name [String]
5
+ # @param index [String]
6
+ # @param message [Symbol, String]
7
+ # @return [void]
8
+ def has_unique_attribute(attribute_name, # rubocop:disable Naming/PredicateName
9
+ index: default_index_name_for_attribute(attribute_name),
10
+ message: :taken)
11
+ assert_unique_index_defined!(index)
12
+
13
+ handle_unique_attribute_on_save(attribute_name, index, message)
14
+ handle_unique_attribute_on_save!(attribute_name, index, message)
15
+ end
16
+
17
+ private
18
+
19
+ # @param index_name [String]
20
+ # @return [void]
21
+ def assert_unique_index_defined!(index_name)
22
+ index = connection.indexes(table_name).find { |index_definition| index_definition.name == index_name }
23
+
24
+ raise ArgumentError, "#{name} does not have index: `#{index_name}`" if index.nil?
25
+ raise ArgumentError, "#{name} defines an index `#{index_name}`, but it is not unique" unless index.unique
26
+ end
27
+
28
+ # @param attribute_name [String]
29
+ # @return [String]
30
+ def default_index_name_for_attribute(attribute_name)
31
+ "index_#{table_name}_on_#{attribute_name}"
32
+ end
33
+
34
+ # @param attribute_name [String]
35
+ # @param index_name [String]
36
+ # @param message [Symbol, String]
37
+ # @return [void]
38
+ def handle_unique_attribute_on_save(attribute_name, index_name, message)
39
+ existing_method = instance_method(:save)
40
+
41
+ define_method(:save) do |*args|
42
+ existing_method.bind(self).call(*args)
43
+ rescue ActiveRecord::RecordNotUnique => error
44
+ if error.message.include?(index_name)
45
+ errors.add(attribute_name, message)
46
+
47
+ return false
48
+ end
49
+
50
+ raise error
51
+ end
52
+ end
53
+
54
+ # @param attribute_name [String]
55
+ # @param index_name [String]
56
+ # @param message [Symbol, String]
57
+ # @return [void]
58
+ def handle_unique_attribute_on_save!(attribute_name, index_name, message)
59
+ existing_method = instance_method(:save!)
60
+
61
+ define_method(:save!) do |*args|
62
+ existing_method.bind(self).call(*args)
63
+ rescue ActiveRecord::RecordNotUnique => error
64
+ if error.message.include?(index_name)
65
+ errors.add(attribute_name, message)
66
+
67
+ raise ActiveRecord::RecordInvalid, self
68
+ end
69
+
70
+ raise error
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HasUniqueAttribute
4
+ VERSION = '0.1.0'
5
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_unique_attribute
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mihail-K
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-07-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-performance
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Adds custom handling for database uniqueness constraints to ActiveRecord.
98
+ email: []
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - ".gitignore"
104
+ - ".rspec"
105
+ - ".rubocop.yml"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - README.md
110
+ - Rakefile
111
+ - bin/console
112
+ - bin/rspec
113
+ - bin/rubocop
114
+ - bin/setup
115
+ - has_unique_attribute.gemspec
116
+ - lib/has_unique_attribute.rb
117
+ - lib/has_unique_attribute/version.rb
118
+ homepage: https://github.com/Mihail-K/has_unique_attribute
119
+ licenses: []
120
+ metadata:
121
+ homepage_uri: https://github.com/Mihail-K/has_unique_attribute
122
+ source_code_uri: https://github.com/Mihail-K/has_unique_attribute
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.0.3
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Handle unique attributes safely using the database.
142
+ test_files: []