attr_sequence 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 +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: []
|