attr_sequence 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +4 -0
- data/MIT-LICENSE.md +20 -0
- data/README.md +235 -0
- data/lib/attr_sequence/active_record.rb +1 -0
- data/lib/attr_sequence/attr_sequence.rb +68 -0
- data/lib/attr_sequence/configuration.rb +19 -0
- data/lib/attr_sequence/generator.rb +82 -0
- data/lib/attr_sequence/version.rb +16 -0
- data/lib/attr_sequence.rb +35 -0
- data/lib/generators/attr_sequence/initializer/initializer_generator.rb +14 -0
- data/lib/generators/attr_sequence/initializer/templates/initializer.rb +4 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5dd41bbcae7b5ff5580d666c830057a8e2d78506
|
4
|
+
data.tar.gz: cd9e7655afcc288c665ba4217749f8d875b52d84
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ac2121044636d2bbf40bc85869d1e65e3e48cda41f144e5d5656cbbd838618c70331f68434318811b8e5885c52c3ca324ee72c4f06aa686c3bc3a6f132ef7ece
|
7
|
+
data.tar.gz: 2be94b1269c7a4c3a3d3caee6f1b640525752ca25182fd56e406ba5ef976f03bc6a941357c4257b4bc3d893ae8c128ac49c0c534786cc5ceea8006d02ad6dac8
|
data/CHANGELOG.md
ADDED
data/MIT-LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018 Brightcommerce, Inc. All rights reserved.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
# AttrSequence
|
2
|
+
|
3
|
+
AttrSequence is an ActiveRecord concern that generates scoped sequential numbers for models. This gem provides an `attr_sequence` macro that automatically assigns a unique, sequential number to each record. The sequential number is not a replacement for the database primary key, but rather adds another way to retrieve the object without exposing the primary key.
|
4
|
+
|
5
|
+
AttrSequence has been extracted from the Brightcommerce platform and is now used in multiple other software projects.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
To install add the line to your `Gemfile`:
|
10
|
+
|
11
|
+
``` ruby
|
12
|
+
gem 'attr_sequence'
|
13
|
+
```
|
14
|
+
|
15
|
+
And run `bundle install`.
|
16
|
+
|
17
|
+
The following configuration defaults are used by AttrSequence:
|
18
|
+
|
19
|
+
``` ruby
|
20
|
+
AttrSequence.configure do |config|
|
21
|
+
config.column = :number
|
22
|
+
config.start_at = 1
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
You can override them by generating an initializer using the following command:
|
27
|
+
|
28
|
+
``` bash
|
29
|
+
rails generate attr_sequence:initializer
|
30
|
+
```
|
31
|
+
|
32
|
+
This will generate an initializer file in your project's `config/initializers` called `attr_sequence.rb` directory.
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
It's generally a bad practice to expose your primary keys to the world in your URLs. However, it is often appropriate to number objects in sequence (in the context of a parent object).
|
37
|
+
|
38
|
+
For example, given a Question model that has many Answers, it makes sense to number answers sequentially for each individual question. You can achieve this with AttrSequence:
|
39
|
+
|
40
|
+
``` ruby
|
41
|
+
class Question < ActiveRecord::Base
|
42
|
+
has_many :answers
|
43
|
+
end
|
44
|
+
|
45
|
+
class Answer < ActiveRecord::Base
|
46
|
+
include AttrSequence
|
47
|
+
belongs_to :question
|
48
|
+
attr_sequence scope: :question_id
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
To autoload AttrSequence for all models, add the following to an initializer:
|
53
|
+
|
54
|
+
``` ruby
|
55
|
+
require 'attr_sequence/active_record'
|
56
|
+
```
|
57
|
+
|
58
|
+
You then don't need to `include AttrSequence` in any model.
|
59
|
+
|
60
|
+
To add a sequential number to a model, first add an integer column called `:number` to the model (or you many name the column anything you like and override the default). For example:
|
61
|
+
|
62
|
+
``` bash
|
63
|
+
rails generate migration add_number_to_answers number:integer
|
64
|
+
rake db:migrate
|
65
|
+
```
|
66
|
+
|
67
|
+
Then, include the concern module and call the `attr_sequence` macro in your model class:
|
68
|
+
|
69
|
+
``` ruby
|
70
|
+
class Answer < ActiveRecord::Base
|
71
|
+
include AttrSequence
|
72
|
+
belongs_to :question
|
73
|
+
attr_sequence scope: :question_id
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
The scope option can be any attribute, but will typically be the foreign key of an associated parent object. You can even scope by multiple columns for polymorphic relationships:
|
78
|
+
|
79
|
+
``` ruby
|
80
|
+
class Answer < ActiveRecord::Base
|
81
|
+
include AttrSequence
|
82
|
+
belongs_to :questionable, polymorphic: true
|
83
|
+
attr_sequence scope: [:questionable_id, :questionable_type]
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
Multiple sequences can be defined by using the macro multiple times:
|
88
|
+
|
89
|
+
``` ruby
|
90
|
+
class Answer < ActiveRecord::Base
|
91
|
+
include AttrSequence
|
92
|
+
belongs_to :account
|
93
|
+
belongs_to :question
|
94
|
+
|
95
|
+
attr_sequence column: :question_answer_number, scope: :question_id
|
96
|
+
attr_sequence column: :account_answer_number, scope: :account_id
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
## Schema and data integrity
|
101
|
+
|
102
|
+
*This gem is only concurrent-safe for PostgreSQL databases.* For other database systems, unexpected behavior may occur if you attempt to create records concurrently.
|
103
|
+
|
104
|
+
You can mitigate this somewhat by applying a unique index to your sequential number column (or a multicolumn unique index on sequential number and scope columns, if you are using scopes). This will ensure that you can never have duplicate sequential numbers within a scope, causing concurrent updates to instead raise a uniqueness error at the database-level.
|
105
|
+
|
106
|
+
It is also a good idea to apply a not-null constraint to your sequential number column as well if you never intend to skip it.
|
107
|
+
|
108
|
+
Here is an example migration for an `Answer` model that has a `:number` scoped to a `Question`:
|
109
|
+
|
110
|
+
``` ruby
|
111
|
+
# app/db/migrations/20180101000000_create_answers.rb
|
112
|
+
class CreateAnswers < ActiveRecord::Migration
|
113
|
+
def change
|
114
|
+
create_table :answers do |table|
|
115
|
+
table.references :question
|
116
|
+
table.column :number, :integer, null: false
|
117
|
+
table.index [:number, :question_id], unique: true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
## Configuration
|
124
|
+
|
125
|
+
### Overriding the default sequential ID column
|
126
|
+
|
127
|
+
By default, AttrSequence uses the `number` column and assumes it already exists. If you wish to store the sequential number in different integer column, simply specify the column name with the `:column` option:
|
128
|
+
|
129
|
+
``` ruby
|
130
|
+
attr_sequence scope: :question_id, column: :my_sequential_id
|
131
|
+
```
|
132
|
+
|
133
|
+
### Starting the sequence at a specific number
|
134
|
+
|
135
|
+
By default, AttrSequence begins sequences with 1. To start at a different integer, simply set the `start_at` option:
|
136
|
+
|
137
|
+
``` ruby
|
138
|
+
attr_sequence start_at: 1000
|
139
|
+
```
|
140
|
+
|
141
|
+
You may also pass a lambda to the `start_at` option:
|
142
|
+
|
143
|
+
``` ruby
|
144
|
+
attr_sequence start_at: lambda { |r| r.computed_start_value }
|
145
|
+
```
|
146
|
+
|
147
|
+
### Indexing the sequential number column
|
148
|
+
|
149
|
+
For optimal performance, it's a good idea to index the sequential number column on sequenced models.
|
150
|
+
|
151
|
+
### Skipping sequential ID generation
|
152
|
+
|
153
|
+
If you'd like to skip generating a sequential number under certain conditions, you may pass a lambda to the `skip` option:
|
154
|
+
|
155
|
+
``` ruby
|
156
|
+
attr_sequence skip: lambda { |r| r.score == 0 }
|
157
|
+
```
|
158
|
+
|
159
|
+
## Example
|
160
|
+
|
161
|
+
Suppose you have a question model that has many answers. This example demonstrates how to use AttrSequence to enable access to the nested answer resource via its sequential number.
|
162
|
+
|
163
|
+
``` ruby
|
164
|
+
# app/models/question.rb
|
165
|
+
class Question < ActiveRecord::Base
|
166
|
+
has_many :answers
|
167
|
+
end
|
168
|
+
|
169
|
+
# app/models/answer.rb
|
170
|
+
class Answer < ActiveRecord::Base
|
171
|
+
include AttrSequence
|
172
|
+
belongs_to :question
|
173
|
+
attr_sequence scope: :question_id
|
174
|
+
|
175
|
+
# Automatically use the sequential number in URLs
|
176
|
+
def to_param
|
177
|
+
self.number.to_s
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# config/routes.rb
|
182
|
+
resources :questions do
|
183
|
+
resources :answers
|
184
|
+
end
|
185
|
+
|
186
|
+
# app/controllers/answers_controller.rb
|
187
|
+
class AnswersController < ApplicationController
|
188
|
+
def show
|
189
|
+
@question = Question.find(params[:question_id])
|
190
|
+
@answer = @question.answers.find_by(number: params[:id])
|
191
|
+
end
|
192
|
+
end
|
193
|
+
```
|
194
|
+
|
195
|
+
Now, answers are accessible via their sequential numbers:
|
196
|
+
|
197
|
+
```
|
198
|
+
http://example.com/questions/5/answers/1 # Good
|
199
|
+
```
|
200
|
+
|
201
|
+
instead of by their primary keys:
|
202
|
+
|
203
|
+
```
|
204
|
+
http://example.com/questions/5/answer/32454 # Bad
|
205
|
+
```
|
206
|
+
|
207
|
+
## Dependencies
|
208
|
+
|
209
|
+
AttrSequence gem has the following runtime dependencies:
|
210
|
+
- activerecord >= 5.1.4
|
211
|
+
- activesupport >= 5.1.4
|
212
|
+
|
213
|
+
## Compatibility
|
214
|
+
|
215
|
+
Tested with MRI 2.4.2 against Rails 5.2.2.
|
216
|
+
|
217
|
+
## Contributing
|
218
|
+
|
219
|
+
1. Fork it
|
220
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
221
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
222
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
223
|
+
5. Create new Pull Request
|
224
|
+
|
225
|
+
## Credit
|
226
|
+
|
227
|
+
This gem was written and is maintained by [Jurgen Jocubeit](https://github.com/JurgenJocubeit), CEO and President Brightcommerce, Inc.
|
228
|
+
|
229
|
+
## License
|
230
|
+
|
231
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
232
|
+
|
233
|
+
## Copyright
|
234
|
+
|
235
|
+
Copyright 2018 Brightcommerce, Inc.
|
@@ -0,0 +1 @@
|
|
1
|
+
ActiveRecord::Base.send :include, AttrSequence
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative './generator'
|
2
|
+
require 'active_support/concern'
|
3
|
+
require 'active_support/core_ext/hash/slice'
|
4
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
5
|
+
|
6
|
+
module AttrSequence
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
SequenceColumnExists = Class.new(StandardError)
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
# Public: Defines ActiveRecord callbacks to set a sequential number scoped
|
13
|
+
# on a specific class.
|
14
|
+
#
|
15
|
+
# Can be called multiple times to add hooks for different column names.
|
16
|
+
#
|
17
|
+
# options - The Hash of options for configuration:
|
18
|
+
# :scope - The Symbol representing the columm on which the
|
19
|
+
# number should be scoped (default: nil)
|
20
|
+
# :column - The Symbol representing the column that stores the
|
21
|
+
# number (default: :number)
|
22
|
+
# :start_at - The Integer value at which the sequence should
|
23
|
+
# start (default: 1)
|
24
|
+
# :skip - Skips the number generation when the lambda
|
25
|
+
# expression evaluates to nil. Gets passed the
|
26
|
+
# model object
|
27
|
+
#
|
28
|
+
# Examples
|
29
|
+
#
|
30
|
+
# class Answer < ActiveRecord::Base
|
31
|
+
# include AttrSequence
|
32
|
+
# belongs_to :question
|
33
|
+
# attr_sequence scope: :question_id
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# Returns nothing.
|
37
|
+
def attr_sequence(options = {})
|
38
|
+
unless defined?(sequence_options)
|
39
|
+
mattr_accessor :sequence_options, instance_accessor: false
|
40
|
+
self.sequence_options = []
|
41
|
+
|
42
|
+
before_save :set_numbers
|
43
|
+
end
|
44
|
+
|
45
|
+
default_options = {column: AttrSequence.column, start_at: AttrSequence.start_at}
|
46
|
+
options = default_options.merge(options)
|
47
|
+
column_name = options[:column]
|
48
|
+
|
49
|
+
if sequence_options.any? {|options| options[:column] == column_name}
|
50
|
+
raise(SequenceColumnExists, <<-MSG.squish)
|
51
|
+
Tried to set #{column_name} as a sequence but there was already a
|
52
|
+
definition here. Did you accidentally call attr_sequence multiple
|
53
|
+
times on the same column?
|
54
|
+
MSG
|
55
|
+
else
|
56
|
+
sequence_options << options
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def set_numbers
|
64
|
+
self.class.base_class.sequence_options.each do |options|
|
65
|
+
AttrSequence::Generator.new(self, options).set
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module AttrSequence
|
2
|
+
class Configuration
|
3
|
+
def column
|
4
|
+
@column ||= :number
|
5
|
+
end
|
6
|
+
|
7
|
+
def column=(value)
|
8
|
+
@column = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def start_at
|
12
|
+
@start_at ||= 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_at=(value)
|
16
|
+
@start_at = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module AttrSequence
|
2
|
+
class Generator
|
3
|
+
attr_reader :record, :scope, :column, :start_at, :skip
|
4
|
+
|
5
|
+
def initialize(record, options = {})
|
6
|
+
@record = record
|
7
|
+
@scope = options[:scope]
|
8
|
+
@column = options[:column].to_sym
|
9
|
+
@start_at = options[:start_at]
|
10
|
+
@skip = options[:skip]
|
11
|
+
end
|
12
|
+
|
13
|
+
def set
|
14
|
+
return if number_set? || skip?
|
15
|
+
lock_table
|
16
|
+
record.send(:"#{column}=", next_number)
|
17
|
+
end
|
18
|
+
|
19
|
+
def number_set?
|
20
|
+
!record.send(column).nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def skip?
|
24
|
+
skip && skip.call(record)
|
25
|
+
end
|
26
|
+
|
27
|
+
def next_number
|
28
|
+
next_number_in_sequence.tap do |number|
|
29
|
+
number += 1 until unique?(number)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def next_number_in_sequence
|
34
|
+
start_at = self.start_at.respond_to?(:call) ? self.start_at.call(record) : self.start_at
|
35
|
+
return start_at unless last_record = find_last_record
|
36
|
+
max(last_record.send(column) + 1, start_at)
|
37
|
+
end
|
38
|
+
|
39
|
+
def unique?(number)
|
40
|
+
build_scope(*scope) do
|
41
|
+
rel = base_relation
|
42
|
+
rel = rel.where("NOT number = ?", record.number) if record.persisted?
|
43
|
+
rel.where(column => number)
|
44
|
+
end.count == 0
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def lock_table
|
50
|
+
if postgresql?
|
51
|
+
record.class.connection.execute("LOCK TABLE #{record.class.table_name} IN EXCLUSIVE MODE")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def postgresql?
|
56
|
+
defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) &&
|
57
|
+
record.class.connection.instance_of?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
58
|
+
end
|
59
|
+
|
60
|
+
def base_relation
|
61
|
+
record.class.base_class.unscoped
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_last_record
|
65
|
+
build_scope(*scope) do
|
66
|
+
base_relation.
|
67
|
+
where("#{column.to_s} IS NOT NULL").
|
68
|
+
order("#{column.to_s} DESC")
|
69
|
+
end.first
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_scope(*columns)
|
73
|
+
rel = yield
|
74
|
+
columns.each { |c| rel = rel.where(c => record.send(c.to_sym)) }
|
75
|
+
rel
|
76
|
+
end
|
77
|
+
|
78
|
+
def max(*values)
|
79
|
+
values.to_a.max
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AttrSequence
|
2
|
+
module Version
|
3
|
+
Major = 1
|
4
|
+
Minor = 0
|
5
|
+
Revision = 0
|
6
|
+
Prerelease = nil
|
7
|
+
Compact = [Major, Minor, Revision, Prerelease].compact.join('.')
|
8
|
+
Summary = "AttrSequence v#{Compact}"
|
9
|
+
Description = "An ActiveRecord concern that generates scoped sequential IDs for models."
|
10
|
+
Author = "Jurgen Jocubeit"
|
11
|
+
Email = "support@brightcommerce.com"
|
12
|
+
Homepage = "https://github.com/brightcommerce/attr_sequence"
|
13
|
+
Metadata = {'copyright' => 'Copyright 2018 Brightcommerce, Inc. All Rights Reserved.'}
|
14
|
+
License = "MIT"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'attr_sequence/attr_sequence'
|
2
|
+
require 'attr_sequence/configuration'
|
3
|
+
require 'attr_sequence/version'
|
4
|
+
|
5
|
+
module AttrSequence
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
@@configuration = nil
|
9
|
+
|
10
|
+
def self.configure
|
11
|
+
@@configuration = Configuration.new
|
12
|
+
yield(configuration) if block_given?
|
13
|
+
configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configuration
|
17
|
+
@@configuration || configure
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.method_missing(method_sym, *arguments, &block)
|
21
|
+
if configuration.respond_to?(method_sym)
|
22
|
+
configuration.send(method_sym)
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.respond_to?(method_sym, include_private = false)
|
29
|
+
if configuration.respond_to?(method_sym, include_private)
|
30
|
+
true
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module AttrSequence
|
4
|
+
class InitializerGenerator < ::Rails::Generators::Base
|
5
|
+
|
6
|
+
namespace "attr_sequence:initializer"
|
7
|
+
source_root File.join(File.dirname(__FILE__), 'templates')
|
8
|
+
|
9
|
+
def create_initializer_file
|
10
|
+
template 'initializer.rb', 'config/initializers/attr_sequence.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attr_sequence
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jurgen Jocubeit
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-12-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.1.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.1.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 5.1.4
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 5.1.4
|
41
|
+
description: An ActiveRecord concern that generates scoped sequential IDs for models.
|
42
|
+
email: support@brightcommerce.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- CHANGELOG.md
|
48
|
+
- MIT-LICENSE.md
|
49
|
+
- README.md
|
50
|
+
- lib/attr_sequence.rb
|
51
|
+
- lib/attr_sequence/active_record.rb
|
52
|
+
- lib/attr_sequence/attr_sequence.rb
|
53
|
+
- lib/attr_sequence/configuration.rb
|
54
|
+
- lib/attr_sequence/generator.rb
|
55
|
+
- lib/attr_sequence/version.rb
|
56
|
+
- lib/generators/attr_sequence/initializer/initializer_generator.rb
|
57
|
+
- lib/generators/attr_sequence/initializer/templates/initializer.rb
|
58
|
+
homepage: https://github.com/brightcommerce/attr_sequence
|
59
|
+
licenses:
|
60
|
+
- MIT
|
61
|
+
metadata:
|
62
|
+
copyright: Copyright 2018 Brightcommerce, Inc. All Rights Reserved.
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '2.3'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.6.13
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: AttrSequence v1.0.0
|
83
|
+
test_files: []
|