prefixed_ids 1.0.1 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab4ea5b61773281d37a10dc9f1dc429f0da2d0f7ed10240c4ae4a17fe3219df9
4
- data.tar.gz: 4a37b8721a3e34cdf4446b5a83ab8a899c2d6f0bf20c6b72b9d37fa884d04e35
3
+ metadata.gz: 3bad6535e46cad00a977806102164ad2f8d79dae1f9d24beb50c12888829c5d6
4
+ data.tar.gz: a50ee9b602318c9a412887ddfd28274848eb5cdd2e5465e40ef7357bb11b2bd1
5
5
  SHA512:
6
- metadata.gz: ce60408ac4ea95916a8915f82b11ecf52ad51e01f9af1cbc626891457e3318fcf006eca7bb87bc02d36804b1b20e4d1fbbfa2d761a4ec1a073f75c8c4a29a0d3
7
- data.tar.gz: '06825f2e2d69c3576b842235ef1faf584b7f371fa75b7e82638d7d9ced3d649b3b0f1bd96b56126d13170a1f46ec410576ba5370e23df871ae3af17796d56a29'
6
+ metadata.gz: 6b0f42366a454e83682535538d072ae2bd1bf166386dcdfe767d75f40046cdfa466c0b763b86d6a1e5475fcff9c5b42970a5e1f5ae876ba56b1d55ca034713b5
7
+ data.tar.gz: 66d904378b4db97609cdd8db76c23fe765a30699c8e4f65b0cb85c656eaff486ab3efa05f74908e7694b7840000682c58e8bd1a96ff6da4437b1f6566c29ada7
data/README.md CHANGED
@@ -24,27 +24,43 @@ gem 'prefixed_ids'
24
24
 
25
25
  ## 📝 Usage
26
26
 
27
- First, you'll need to generate a migration to add the prefix_id column to your model(s).
27
+ Add `has_prefix_id :my_prefix` to your models to autogenerate prefixed IDs.
28
28
 
29
29
  ```ruby
30
- class AddPrefixIdToUsers< ActiveRecord::Migration
31
- def change
32
- add_index :users, :prefix_id, unique: true
33
- end
30
+ class User < ApplicationRecord
31
+ has_prefix_id :user
34
32
  end
35
33
  ```
36
34
 
37
- It's important the `prefix_id` column is indexed and unique.
35
+ This will generate a value like `user_1234abcd`.
36
+
37
+ To query using the prefixed ID, simply you can use either `find` or `find_by_prefixed_id`:
38
+
39
+ ```ruby
40
+ User.find("user_5vJjbzXq9KrLEMm32iAnOP0xGDYk6dpe")
41
+ User.find_by_prefix_id("user_5vJjbzXq9KrLEMm32iAnOP0xGDYk6dpe")
42
+ ```
43
+
44
+ We also override `to_param` by default so it'll be used in URLs automatically.
38
45
 
39
- Then you can add `has_prefix_id :my_prefix` to your models to autogenerate prefixed IDs.
46
+ To disable find and to_param overrides, simply pass in the options:
40
47
 
41
48
  ```ruby
42
49
  class User < ApplicationRecord
43
- has_prefix_id :user
50
+ has_prefix_id :user, override_find: false, override_param: false
44
51
  end
45
52
  ```
46
53
 
47
- This will generate a value like `user_1234abcd` in the User's `prefix_id` column.
54
+ ### Generic lookup
55
+
56
+ Imagine you have a prefixed ID but you don't know which model it belongs to.
57
+
58
+ ```ruby
59
+ PrefixedIds.find("user_5vJjbzXq9KrLEMm3")
60
+ #=> #<User>
61
+ PrefixedIds.find("acct_2iAnOP0xGDYk6dpe")
62
+ #=> #<Account>
63
+ ```
48
64
 
49
65
  ### Customizing
50
66
 
@@ -52,7 +68,7 @@ You can customize the prefix, length, and attribute name for PrefixedIds.
52
68
 
53
69
  ```ruby
54
70
  class Account < ApplicationRecord
55
- has_prefix_id :acct, attribute: :my_id, length: 32
71
+ has_prefix_id :acct, minimum_length: 32, override_find: false, to_param: false
56
72
  end
57
73
  ```
58
74
 
data/lib/prefixed_ids.rb CHANGED
@@ -1,29 +1,89 @@
1
1
  require "prefixed_ids/version"
2
2
  require "prefixed_ids/engine"
3
3
 
4
+ require "hashids"
5
+
4
6
  module PrefixedIds
5
- MINIMUM_TOKEN_LENGTH = 24
7
+ class Error < StandardError; end
8
+
9
+ autoload :PrefixId, "prefixed_ids/prefix_id"
10
+
11
+ TOKEN = 123
12
+ DELIMITER = "_"
13
+
14
+ mattr_accessor :alphabet, default: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
15
+ mattr_accessor :minimum_length, default: 24
6
16
 
7
- class MinimumLengthError < StandardError; end
17
+ mattr_accessor :models, default: {}
18
+
19
+ def self.find(prefix_id)
20
+ prefix, _ = split_id(prefix_id)
21
+ models.fetch(prefix).find_by_prefix_id(prefix_id)
22
+ rescue KeyError
23
+ raise Error, "Unable to find model with prefix `#{prefix}`. Available prefixes are: #{models.keys.join(", ")}"
24
+ end
25
+
26
+ # Splits a prefixed ID into its prefix and ID
27
+ def self.split_id(prefix_id)
28
+ prefix, _, id = prefix_id.to_s.rpartition(DELIMITER)
29
+ [prefix, id]
30
+ end
8
31
 
32
+ # Adds `has_prefix_id` method
33
+ module Rails
34
+ extend ActiveSupport::Concern
35
+
36
+ included do
37
+ class_attribute :_prefix_id
38
+ end
39
+
40
+ class_methods do
41
+ def has_prefix_id(prefix, override_find: true, override_param: true, **options)
42
+ include Attribute
43
+ include Finder if override_find
44
+ include ToParam if override_param
45
+ self._prefix_id = PrefixId.new(self, prefix, **options)
46
+
47
+ # Register with PrefixedIds to support PrefixedIds#find
48
+ PrefixedIds.models[prefix.to_s] = self
49
+ end
50
+ end
51
+ end
52
+
53
+ # Included when a module uses `has_prefix_id`
9
54
  module Attribute
10
55
  extend ActiveSupport::Concern
11
56
 
12
- module ClassMethods
13
- def has_prefix_id(prefix, attribute: :prefix_id, length: MINIMUM_TOKEN_LENGTH)
14
- if length < MINIMUM_TOKEN_LENGTH
15
- raise MinimumLengthError, "Token requires a minimum length of #{MINIMUM_TOKEN_LENGTH} characters."
16
- end
57
+ class_methods do
58
+ def find_by_prefix_id(id)
59
+ find_by(id: _prefix_id.decode(id))
60
+ end
17
61
 
18
- # Load securerandom only when has_secure_token is used.
19
- require "active_support/core_ext/securerandom"
20
- define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_prefix_id(prefix, length: length) }
21
- before_create { send("#{attribute}=", self.class.generate_unique_prefix_id(prefix, length: length)) unless send("#{attribute}?") }
62
+ def find_by_prefix_id!(id)
63
+ find_by!(id: _prefix_id.decode(id))
22
64
  end
65
+ end
66
+
67
+ def prefix_id
68
+ self.class._prefix_id.encode(id)
69
+ end
70
+ end
23
71
 
24
- def generate_unique_prefix_id(prefix, length: MINIMUM_TOKEN_LENGTH)
25
- prefix.to_s + "_" + SecureRandom.base58(length)
72
+ module Finder
73
+ extend ActiveSupport::Concern
74
+
75
+ class_methods do
76
+ def find(*ids)
77
+ super(*ids.map { |id| _prefix_id.decode(id) })
26
78
  end
27
79
  end
28
80
  end
81
+
82
+ module ToParam
83
+ extend ActiveSupport::Concern
84
+
85
+ def to_param
86
+ _prefix_id.encode(id)
87
+ end
88
+ end
29
89
  end
@@ -2,7 +2,7 @@ module PrefixedIds
2
2
  class Engine < ::Rails::Engine
3
3
  initializer "prefixed_ids.model" do
4
4
  ActiveSupport.on_load(:active_record) do
5
- include PrefixedIds::Attribute
5
+ include PrefixedIds::Rails
6
6
  end
7
7
  end
8
8
  end
@@ -0,0 +1,24 @@
1
+ module PrefixedIds
2
+ class PrefixId
3
+ attr_reader :hashids, :model, :prefix
4
+
5
+ def initialize(model, prefix, minimum_length: PrefixedIds.minimum_length, alphabet: PrefixedIds.alphabet, **options)
6
+ @alphabet = alphabet
7
+ @model = model
8
+ @prefix = prefix.to_s
9
+ @hashids = Hashids.new(model.table_name, minimum_length)
10
+ end
11
+
12
+ def encode(id)
13
+ prefix + "_" + @hashids.encode(TOKEN, id)
14
+ end
15
+
16
+ # decode returns an array
17
+ def decode(id, fallback: false)
18
+ fallback_value = fallback ? id : nil
19
+ _, id_without_prefix = PrefixedIds.split_id(id)
20
+ decoded_id = @hashids.decode(id_without_prefix).last
21
+ decoded_id || fallback_value
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  module PrefixedIds
2
- VERSION = "1.0.1"
2
+ VERSION = "1.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prefixed_ids
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-17 00:00:00.000000000 Z
11
+ date: 2021-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,6 +24,26 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 6.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: hashids
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: 2.0.0
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: 2.0.0
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: standardrb
29
49
  requirement: !ruby/object:Gem::Requirement
@@ -64,6 +84,7 @@ files:
64
84
  - Rakefile
65
85
  - lib/prefixed_ids.rb
66
86
  - lib/prefixed_ids/engine.rb
87
+ - lib/prefixed_ids/prefix_id.rb
67
88
  - lib/prefixed_ids/version.rb
68
89
  - lib/tasks/prefixed_ids_tasks.rake
69
90
  homepage: https://github.com/excid3/prefixed_ids