prefixed_ids 1.0.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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