encoded_id 1.0.0.rc5 → 1.0.0.rc6
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 +4 -4
- data/CHANGELOG.md +78 -2
- data/README.md +79 -333
- data/context/encoded_id.md +283 -0
- data/lib/encoded_id/alphabet.rb +32 -3
- data/lib/encoded_id/blocklist.rb +90 -0
- data/lib/encoded_id/encoders/base.rb +71 -0
- data/lib/encoded_id/encoders/hash_id.rb +531 -0
- data/lib/encoded_id/encoders/hash_id_consistent_shuffle.rb +110 -0
- data/lib/encoded_id/encoders/hash_id_ordinal_alphabet_separator_guards.rb +270 -0
- data/lib/encoded_id/encoders/hash_id_salt.rb +51 -0
- data/lib/encoded_id/encoders/my_sqids.rb +465 -0
- data/lib/encoded_id/encoders/sqids.rb +42 -0
- data/lib/encoded_id/hex_representation.rb +23 -5
- data/lib/encoded_id/reversible_id.rb +109 -23
- data/lib/encoded_id/version.rb +4 -1
- data/lib/encoded_id.rb +38 -5
- metadata +14 -23
- data/.devcontainer/Dockerfile +0 -9
- data/.devcontainer/compose.yml +0 -8
- data/.devcontainer/devcontainer.json +0 -8
- data/.standard.yml +0 -2
- data/Gemfile +0 -36
- data/Rakefile +0 -20
- data/Steepfile +0 -5
- data/ext/encoded_id/extconf.rb +0 -3
- data/ext/encoded_id/extension.c +0 -123
- data/ext/encoded_id/hashids.c +0 -939
- data/ext/encoded_id/hashids.h +0 -139
- data/lib/encoded_id/hash_id.rb +0 -227
- data/lib/encoded_id/hash_id_consistent_shuffle.rb +0 -27
- data/lib/encoded_id/hash_id_salt.rb +0 -15
- data/lib/encoded_id/ordinal_alphabet_separator_guards.rb +0 -90
- data/rbs_collection.yaml +0 -24
- data/sig/encoded_id.rbs +0 -189
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e5135a9e76cfd6a49cd14921bfa277deb83eb05b9e753efdb23e4145b3f5f7c7
|
|
4
|
+
data.tar.gz: ed8a43d5e654d9fd947d7b9b0a37aacc18c3b713c9303c9d6dbbf22b890eb965
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 91e58ac5b6df75e7da94f8ea4868967e93f6b8c76ec94cb6fc821a60ab33dfe704b19ad43d41916f8896d5db982f6d610e48335f8e9d03129f0422a7b0f5cd60
|
|
7
|
+
data.tar.gz: f427c6e2ca883e522e80a934053a5b5486dc75be3a6babf5e55f878d85fe8e31a0a1c1af98b4bbda8a5f310be18ac5ea2b2ec8edf322b54584d78b2126c92c15
|
data/CHANGELOG.md
CHANGED
|
@@ -4,9 +4,44 @@
|
|
|
4
4
|
|
|
5
5
|
### Breaking changes
|
|
6
6
|
|
|
7
|
-
- `ReversibleId` now no longer downcases the encodedid input string by default on decode, ie the `decode` option `downcase` is now `false`. In a future release the `downcase` option will be removed.
|
|
7
|
+
- `ReversibleId` now no longer downcases the encodedid input string by default on decode, ie the `decode` option `downcase` is now `false`. In a future release the `downcase` option will be removed.
|
|
8
|
+
- The default encoding engine is now `:sqids` to reflect the official "deprecated" status of `Hashid`s (see https://sqids.org/faq#why-hashids)
|
|
9
|
+
- Ruby < 3.2 support dropped. The minimum supported Ruby version is now 3.2.0
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
**Important!!: `:sqids` are not compatible with `:hashids`, DO NOT CHANGE FROM ONE TO THE OTHER AFTER GOING LIVE.**
|
|
12
|
+
|
|
13
|
+
## [1.0.0.rc6] - 2025-11-17
|
|
14
|
+
|
|
15
|
+
### Breaking changes
|
|
16
|
+
|
|
17
|
+
- Empty array inputs will now raise `InvalidInputError`
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Added support for [Sqids](https://sqids.org) as an alternative ID encoding engine. The default remains HashIds for backward compatibility.
|
|
22
|
+
- New encoder abstraction layer allows switching between HashIds and Sqids via the `encoder: :sqids` or `encoder: :hashids` parameter to `ReversibleId.new`.
|
|
23
|
+
- Support for blocklists in both HashIds and Sqids encoders to prevent generating IDs containing specific words. Use the `blocklist` parameter with a `Set` or `Array` of strings to `ReversibleId.new`. For Hashids encodings, an error will be raised if a generated ID contains a blocklisted word. For Sqids a new ID is generated that does not contain the block word.
|
|
24
|
+
|
|
25
|
+
### Added (Rails integration)
|
|
26
|
+
|
|
27
|
+
- Merged `encoded_id-rails` gem into the monorepo
|
|
28
|
+
- Support for configuring the encoder and blocklist options in Rails through the configuration class
|
|
29
|
+
- `#encoded_id` now defaults to returning an 'annotated' ID, one in which a prefix is added to the encoded ID to indicate the 'type' of the record the ID represents. This can be disabled. IDs generated by older versions of this gem will decode correctly. But note that IDs generated by this version onwards will not decode correctly by older versions of this gem so make sure to disable annotation if you need to support older versions of this gem.
|
|
30
|
+
- New `EncodedId::Rails::Persists` module which adds hooks to the model to persist the encoded ID to the DB (see docs).
|
|
31
|
+
- `#encoded_id_hash` has been added to return only the encoded ID without an annotation prefix. If annotation is disabled, this method is basically an alias to `#encoded_id`.
|
|
32
|
+
- `.find_all_by_encoded_id` has been added to return all records matching the given encoded ID. This will return all matching records whose IDs are encoded in the encoded_id. Missing records are ignored.
|
|
33
|
+
- `.find_all_by_encoded_id!` like `.find_all_by_encoded_id` but raises an `ActiveRecord::RecordNotFound` exception if *any* of the records are not found.
|
|
34
|
+
- `Configuration#model_to_param_returns_encoded_id` to allow `EncodedId::Rails::Model` inclusion to also bring in `EncodedId::Rails::PathParam` automatically.
|
|
35
|
+
|
|
36
|
+
### Changed (Rails integration)
|
|
37
|
+
|
|
38
|
+
- `#name_for_encoded_id_slug` no longer provides a default implementation, it is up to the user to define this method, or configure the gem to use a different method name.
|
|
39
|
+
- `#slugged_encoded_id` no longer takes a `with:` parameter. To specify the name of the method to call to generate the slug, use the `slug_value_method_name` configuration option.
|
|
40
|
+
|
|
41
|
+
### Fixed (Rails integration)
|
|
42
|
+
|
|
43
|
+
- `#decode_encoded_id` now raises if the encoded ID is not a string.
|
|
44
|
+
- Handle more cases where a record held onto a memoized `encoded_id` even though its `id` had changed
|
|
10
45
|
|
|
11
46
|
## [1.0.0.rc5] - 2025-04-09
|
|
12
47
|
|
|
@@ -48,3 +83,44 @@
|
|
|
48
83
|
## [0.1.0] - 2022-10-11
|
|
49
84
|
|
|
50
85
|
- Initial release
|
|
86
|
+
|
|
87
|
+
## Rails Integration History
|
|
88
|
+
|
|
89
|
+
## [0.6.2] - 2023-02-09
|
|
90
|
+
|
|
91
|
+
- Fix `encoded_id` memoization clearing when record is duplicated
|
|
92
|
+
|
|
93
|
+
## [0.6.1] - 2023-02-09
|
|
94
|
+
|
|
95
|
+
- Fix `#encoded_id` to return nil if `#id` is nil
|
|
96
|
+
- Ensure `encoded_id` memoization is cleared when record is duplicated, or id changes
|
|
97
|
+
|
|
98
|
+
## [0.6.0] - 2022-12-21
|
|
99
|
+
|
|
100
|
+
- Rename mixin to `Model`
|
|
101
|
+
- Introduce optional mixins for overriding `#to_param`
|
|
102
|
+
|
|
103
|
+
## [0.5.0] - 2022-12-21
|
|
104
|
+
|
|
105
|
+
- `name_for_encoded_id_slug` no longer uses the return value from name but rather just uses the `class` `name`.
|
|
106
|
+
- If you want to change the name used in the slug, override `name_for_encoded_id_slug`
|
|
107
|
+
|
|
108
|
+
## [0.4.0] - 2022-12-18
|
|
109
|
+
|
|
110
|
+
- Refactor internals, remove any methods not actually related to creating `encoded_id`, (eg `slugged_id` was removed).
|
|
111
|
+
|
|
112
|
+
## [0.3.1] - 2022-12-15
|
|
113
|
+
|
|
114
|
+
- Fix default config
|
|
115
|
+
|
|
116
|
+
## [0.3.0] - 2022-12-15
|
|
117
|
+
|
|
118
|
+
- Updates gem `encoded_id` dependency and fixes configuration
|
|
119
|
+
|
|
120
|
+
## [0.2.0] - 2022-12-14
|
|
121
|
+
|
|
122
|
+
- No notes...
|
|
123
|
+
|
|
124
|
+
## [0.1.0] - 2022-11-17
|
|
125
|
+
|
|
126
|
+
- Initial release of Rails integration
|
data/README.md
CHANGED
|
@@ -1,334 +1,125 @@
|
|
|
1
|
-
# EncodedId
|
|
1
|
+
# EncodedId and EncodedId::Rails
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
|
+

|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# => "p5w9-z27j"
|
|
9
|
-
coder.encode_hex("10f8c")
|
|
10
|
-
# => "w72a-y0az"
|
|
11
|
-
```
|
|
6
|
+
`encoded_id` lets you encode numerical or hex IDs into obfuscated strings that can be used in URLs.
|
|
7
|
+
|
|
8
|
+
`encoded_id-rails` is a Rails integration that provides additional features for using `encoded_id` with ActiveRecord models.
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
👉 **Full documentation available at [encoded-id.onrender.com](https://encoded-id.onrender.com)**
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
## Quick Example
|
|
16
13
|
|
|
17
14
|
```ruby
|
|
18
|
-
|
|
19
|
-
coder
|
|
15
|
+
coder = ::EncodedId::ReversibleId.new(salt: "my-salt")
|
|
16
|
+
coder.encode(123)
|
|
17
|
+
# => "p5w9-z27j"
|
|
20
18
|
|
|
21
|
-
#
|
|
19
|
+
# The encoded strings are reversible
|
|
20
|
+
coder.decode("p5w9-z27j")
|
|
21
|
+
# => [123]
|
|
22
|
+
|
|
23
|
+
# Supports encoding multiple IDs at once
|
|
22
24
|
coder.encode([78, 45])
|
|
23
25
|
# => "z2j7-0dmw"
|
|
24
26
|
|
|
25
|
-
#
|
|
26
|
-
coder.decode("z2j7-0dmw")
|
|
27
|
-
# => [78, 45]
|
|
28
|
-
|
|
29
|
-
# The decoder can be resilient to easily confused characters
|
|
30
|
-
coder.decode("z2j7-Odmw") # (note the capital 'o' instead of zero)
|
|
31
|
-
# => [78, 45]
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Features
|
|
35
|
-
|
|
36
|
-
* 🔄 encoded IDs are reversible (uses Hashids, the old site is here https://github.com/hashids/hashids.github.io))
|
|
37
|
-
* 👥 supports multiple IDs encoded in one encoded string (eg `7aq6-0zqw` decodes to `[78, 45]`)
|
|
38
|
-
* 🔡 supports custom alphabets for the encoded string (at least 16 characters needed)
|
|
39
|
-
- by default uses a variation of the Crockford reduced character set (https://www.crockford.com/base32.html)
|
|
40
|
-
- 👓 easily confused characters (eg `i` and `j`, `0` and `O`, `1` and `I` etc) are mapped to counterpart characters, to help
|
|
41
|
-
avoid common readability mistakes when reading/sharing
|
|
42
|
-
- 🤬 build in profanity limitation
|
|
43
|
-
* 🤓 encoded string can be split into groups of letters to improve human-readability
|
|
44
|
-
- eg `nft9hr834htu` as `nft9-hr83-4htu`
|
|
45
|
-
* 🥽 supports limits on length to prevent resource exhaustion on encoding and decoding
|
|
46
|
-
* configured with sensible defaults
|
|
47
|
-
|
|
48
|
-
I aim for 100% test coverage and have fuzz tested quite extensively. But please report any issues!
|
|
49
|
-
|
|
50
|
-
### Experimental
|
|
51
|
-
|
|
52
|
-
* support for encoding of hex strings (eg UUIDs), including multiple IDs encoded in one string
|
|
53
|
-
|
|
54
|
-
### Performance and benchmarking
|
|
55
|
-
|
|
56
|
-
This gem uses a custom HashId implementation that is significantly faster and more memory-efficient than the original `hashids` gem.
|
|
57
|
-
|
|
58
|
-
For detailed benchmarks and performance metrics, see the [Custom HashId Implementation](#custom-hashid-implementation) section at the end of this README.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
### Rails support `encoded_id-rails`
|
|
62
|
-
|
|
63
|
-
To use with **Rails** check out the [`encoded_id-rails`](https://github.com/stevegeek/encoded_id-rails) gem.
|
|
64
|
-
|
|
65
|
-
```ruby
|
|
27
|
+
# Can also be used with ActiveRecord models
|
|
66
28
|
class User < ApplicationRecord
|
|
67
|
-
include EncodedId::
|
|
29
|
+
include EncodedId::Rails::Model
|
|
30
|
+
|
|
31
|
+
# Optional slug for the encoded ID
|
|
32
|
+
def name_for_encoded_id_slug
|
|
33
|
+
full_name
|
|
34
|
+
end
|
|
68
35
|
end
|
|
69
36
|
|
|
70
|
-
|
|
71
|
-
# => #<User id: 78>
|
|
37
|
+
# Find by encoded ID
|
|
38
|
+
user = User.find_by_encoded_id("p5w9-z27j") # => #<User id: 78>
|
|
39
|
+
user.encoded_id # => "user_p5w9-z27j"
|
|
40
|
+
user.slugged_encoded_id # => "bob-smith--user_p5w9-z27j"
|
|
72
41
|
```
|
|
73
42
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
**Encoded IDs are not secure**. It maybe possible to reverse them via brute-force. They are meant to be used in URLs as
|
|
77
|
-
an obfuscation. The algorithm is not an encryption.
|
|
78
|
-
|
|
79
|
-
Please read more on https://hashids.org/
|
|
43
|
+
## Key Features
|
|
80
44
|
|
|
81
|
-
|
|
45
|
+
* 🔄 **Reversible** - Encoded IDs can be decoded back to the original values
|
|
46
|
+
* 👥 **Multiple IDs** - Encode multiple numeric IDs in one string
|
|
47
|
+
* 🚀 **Choose your encoding** - Supports `Hashids` and `Sqids` out of the box, or use your own custom encoder
|
|
48
|
+
* 👓 **Human-readable** - Character grouping & character mappings of easily confused characters for better readability
|
|
49
|
+
* 🔡 **Custom alphabets** - Use your preferred character set, or a provided default
|
|
50
|
+
* 🚗 **Performance** - Uses an optimized `Hashids` encoder (compared to `hashids` gem) for better performance and less memory usage, and have pushed performance improvements to `Sqids` as well
|
|
51
|
+
* 🤬 **Profanity blocking** - Built-in word blocklist support and optional default lists
|
|
82
52
|
|
|
83
|
-
|
|
84
|
-
- https://github.com/namick/obfuscate_id
|
|
85
|
-
- https://github.com/norman/friendly_id
|
|
86
|
-
- https://github.com/SPBTV/with_uid
|
|
53
|
+
### Rails Integration Features
|
|
87
54
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
$ gem install encoded_id
|
|
97
|
-
|
|
98
|
-
## `EncodedId::ReversibleId.new`
|
|
99
|
-
|
|
100
|
-
To create an instance of the encoder/decoder use `.new` with the `salt` option:
|
|
101
|
-
|
|
102
|
-
```ruby
|
|
103
|
-
coder = EncodedId::ReversibleId.new(
|
|
104
|
-
# The salt is required
|
|
105
|
-
salt: ...,
|
|
106
|
-
# And then the following options are optional
|
|
107
|
-
length: 8,
|
|
108
|
-
split_at: 4,
|
|
109
|
-
split_with: "-",
|
|
110
|
-
alphabet: EncodedId::Alphabet.modified_crockford,
|
|
111
|
-
hex_digit_encoding_group_size: 4 # Experimental
|
|
112
|
-
)
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
Note the `salt` value is required and should be a string of some length (greater than 3 characters). This is used to generate the encoded string.
|
|
116
|
-
|
|
117
|
-
It will need to be the same value when decoding the string back into the original ID. If the salt is changed, the encoded
|
|
118
|
-
strings will be different and possibly decode to different IDs.
|
|
119
|
-
|
|
120
|
-
### Options
|
|
121
|
-
|
|
122
|
-
The encoded ID is configurable. The following can be changed:
|
|
123
|
-
|
|
124
|
-
- the length, eg 8 characters for `p5w9-z27j`
|
|
125
|
-
- the alphabet used in it (min 16 characters)
|
|
126
|
-
- and the number of characters to split the output into and the separator
|
|
127
|
-
|
|
128
|
-
### `length`
|
|
129
|
-
|
|
130
|
-
`length`: the minimum length of the encoded string. The default is 8 characters.
|
|
131
|
-
|
|
132
|
-
The actual length of the encoded string can be longer if the inputs cannot be represented in the minimum length.
|
|
133
|
-
|
|
134
|
-
### `max_length`
|
|
135
|
-
|
|
136
|
-
`max_length`: the maximum length of the encoded string. The default is 128 characters.
|
|
137
|
-
|
|
138
|
-
The maximum length represents both the longest encoded string that will be generated and also a limit on
|
|
139
|
-
the maximum input length that will be decoded. If the encoded string exceeds `max_length` then a
|
|
140
|
-
`EncodedIdLengthError` will be raised. If the input exceeds `max_length` then a `InvalidInputError` will
|
|
141
|
-
be raised. If `max_length` is set to `nil`, then no validation, even using the default will be performed.
|
|
142
|
-
|
|
143
|
-
### `max_inputs_per_id`
|
|
144
|
-
|
|
145
|
-
`max_inputs_per_id`: the maximum amount of IDs to be encoded together. The default is 32.
|
|
146
|
-
|
|
147
|
-
This maximum amount is used to limit:
|
|
148
|
-
- the length of array input passed to `encode`
|
|
149
|
-
- the length of integer array encoded in hex string(s) passed to `encode_hex` function.
|
|
150
|
-
`InvalidInputError` wil be raised when array longer than `max_inputs_per_id` is provided.
|
|
151
|
-
|
|
152
|
-
### `alphabet`
|
|
153
|
-
|
|
154
|
-
`alphabet`: the alphabet used in the encoded string. By default, it uses a variation of the Crockford reduced character set (https://www.crockford.com/base32.html).
|
|
155
|
-
|
|
156
|
-
`alphabet` must be an instance of `EncodedId::Alphabet`.
|
|
157
|
-
|
|
158
|
-
The default alphabet is `EncodedId::Alphabet.modified_crockford`.
|
|
159
|
-
|
|
160
|
-
To create a new alphabet, use `EncodedId::Alphabet.new`:
|
|
161
|
-
|
|
162
|
-
```ruby
|
|
163
|
-
alphabet = EncodedId::Alphabet.new("0123456789abcdef")
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
`EncodedId::Alphabet.new(characters, equivalences)`
|
|
167
|
-
|
|
168
|
-
**characters**
|
|
169
|
-
|
|
170
|
-
`characters`: the characters of the alphabet. Can be a string or array of strings.
|
|
171
|
-
|
|
172
|
-
Note that the `characters` of the alphabet must be at least 16 _unique_ characters long and must not contain any
|
|
173
|
-
whitespace characters.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
```ruby
|
|
177
|
-
alphabet = EncodedId::Alphabet.new("ςερτυθιοπλκξηγφδσαζχψωβνμ")
|
|
178
|
-
coder = ::EncodedId::ReversibleId.new(salt: my_salt, alphabet: alphabet)
|
|
179
|
-
coder.encode(123)
|
|
180
|
-
# => "πφλχ-ψησω"
|
|
181
|
-
```
|
|
55
|
+
* 🏷️ **ActiveRecord integration** - Use with ActiveRecord models
|
|
56
|
+
* 🔑 **Per-model salt** - Use a custom salt for encoding per model
|
|
57
|
+
* 💅 **Slugged IDs** - URL-friendly slugs like `my-product--p5w9-z27j`
|
|
58
|
+
* 🔖 **Annotated IDs** - Model type indicators like `user_p5w9-z27j`
|
|
59
|
+
* 🔍 **Finder methods** - Find records using encoded IDs
|
|
60
|
+
* 🛣️ **URL params** - `to_param` with encoded IDs
|
|
61
|
+
* 🔒 **Safe defaults**: Limits on encoded ID lengths to prevent CPU and memory-intensive encode/decodes eg when used in URLs
|
|
62
|
+
* 💾 **Persistence** - Optional database persistence for efficient lookups
|
|
182
63
|
|
|
183
|
-
Note that larger alphabets can result in shorter encoded strings (but remember that `length` specifies the minimum length
|
|
184
|
-
of the encoded string).
|
|
185
64
|
|
|
186
|
-
|
|
65
|
+
## Standalone Gem
|
|
187
66
|
|
|
188
|
-
You can optionally pass an appropriate character `equivalences` mapping. This is used to map easily confused characters
|
|
189
|
-
to their counterpart.
|
|
190
67
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
- must not be in the alphabet,
|
|
195
|
-
- must map to a character that is in the alphabet.
|
|
196
|
-
|
|
197
|
-
`nil` is the default value which means no equivalences are used.
|
|
198
|
-
|
|
199
|
-
```ruby
|
|
200
|
-
alphabet = EncodedId::Alphabet.new("!@#$%^&*()+-={}", {"_" => "-"})
|
|
201
|
-
coder = ::EncodedId::ReversibleId.new(salt: my_salt, alphabet: alphabet)
|
|
202
|
-
coder.encode(123)
|
|
203
|
-
# => "}*^(-^}*="
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### `split_at` and `split_with`
|
|
207
|
-
|
|
208
|
-
For readability, the encoded string can be split into groups of characters.
|
|
209
|
-
|
|
210
|
-
`split_at`: specifies the number of characters to split the encoded string into. Defaults to 4.
|
|
211
|
-
|
|
212
|
-
`split_with`: specifies the separator to use between the groups. Default is `-`.
|
|
213
|
-
|
|
214
|
-
Set either to `nil` to disable splitting.
|
|
215
|
-
|
|
216
|
-
### `hex_digit_encoding_group_size`
|
|
217
|
-
|
|
218
|
-
**Experimental**
|
|
219
|
-
|
|
220
|
-
`hex_digit_encoding_group_size`: specifies the number of hex digits to encode in a group. Defaults to 4. Can be
|
|
221
|
-
between 1 and 32.
|
|
222
|
-
|
|
223
|
-
Can be used to control the size of the encoded string when encoding hex strings. Larger values will result in shorter
|
|
224
|
-
encoded strings for long inputs, and shorter values will result in shorter encoded strings for smaller inputs.
|
|
225
|
-
|
|
226
|
-
But note that bigger values will also result in larger markers that separate the groups so could end up increasing
|
|
227
|
-
the encoded string length undesirably.
|
|
228
|
-
|
|
229
|
-
See below section `Using with hex strings` for more details.
|
|
230
|
-
|
|
231
|
-
## `EncodedId::ReversibleId#encode`
|
|
232
|
-
|
|
233
|
-
`#encode(id)`: where `id` is an integer or array of integers to encode.
|
|
234
|
-
|
|
235
|
-
```ruby
|
|
236
|
-
coder.encode(123)
|
|
237
|
-
# => "p5w9-z27j"
|
|
68
|
+
```bash
|
|
69
|
+
# Add to Gemfile
|
|
70
|
+
bundle add encoded_id
|
|
238
71
|
|
|
239
|
-
#
|
|
240
|
-
|
|
241
|
-
# => "z2j7-0dmw"
|
|
72
|
+
# Or install directly
|
|
73
|
+
gem install encoded_id
|
|
242
74
|
```
|
|
243
75
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
`#decode(encoded_id)`: where `encoded_id` is a string to decode.
|
|
247
|
-
|
|
248
|
-
```ruby
|
|
249
|
-
# The encoded string can then be reversed back into the original IDs
|
|
250
|
-
coder.decode("z2j7-0dmw")
|
|
251
|
-
# => [78, 45]
|
|
252
|
-
```
|
|
76
|
+
See the [EncodedId API](https://encoded-id.onrender.com/docs/encoded_id/api) documentation for more details.
|
|
253
77
|
|
|
254
|
-
##
|
|
78
|
+
## Rails Integration Gem
|
|
255
79
|
|
|
256
|
-
|
|
80
|
+
```bash
|
|
81
|
+
# Add to Gemfile
|
|
82
|
+
bundle add encoded_id-rails
|
|
257
83
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
coder.encode_hex("10f8c")
|
|
261
|
-
# => "w72a-y0az"
|
|
84
|
+
# Then run the generator
|
|
85
|
+
rails g encoded_id:rails:install
|
|
262
86
|
```
|
|
263
87
|
|
|
264
|
-
|
|
265
|
-
integer equivalent. In other words the input is converted into an array of integers and encoded as normal with the
|
|
266
|
-
`encode` method.
|
|
88
|
+
See the [Rails Integration](https://encoded-id.onrender.com/docs/encoded_id_rails) documentation for more details.
|
|
267
89
|
|
|
268
|
-
|
|
269
|
-
respectively, ie `encode` is called with `[15, 1]`.
|
|
90
|
+
## Security Note
|
|
270
91
|
|
|
271
|
-
|
|
272
|
-
marker is equal to an integer value which is 1 larger than the maximum value the hex digit encoding group size can
|
|
273
|
-
represent (ie it is `2^(hex_digit_encoding_group_size * 4)`).
|
|
92
|
+
**Encoded IDs are not secure**. They are meant to provide obfuscation, not encryption. Do not use them as a security mechanism.
|
|
274
93
|
|
|
275
|
-
|
|
94
|
+
## Compare to Alternate Gems
|
|
276
95
|
|
|
277
|
-
|
|
278
|
-
|
|
96
|
+
- [prefixed_ids](https://github.com/excid3/prefixed_ids)
|
|
97
|
+
- [obfuscate_id](https://github.com/namick/obfuscate_id)
|
|
98
|
+
- [friendly_id](https://github.com/norman/friendly_id)
|
|
99
|
+
- [with_uid](https://github.com/SPBTV/with_uid)
|
|
100
|
+
- [bullet_train-obfuscates_id](https://github.com/bullet-train-co/bullet_train-core/blob/main/bullet_train-obfuscates_id/app/models/concerns/obfuscates_id.rb)
|
|
279
101
|
|
|
280
|
-
|
|
102
|
+
For a detailed comparison, see the [Compared to Other Gems](https://encoded-id.onrender.com/docs/compared-to) documentation page.
|
|
281
103
|
|
|
282
|
-
|
|
104
|
+
## Documentation
|
|
283
105
|
|
|
284
|
-
|
|
285
|
-
# UUIDs will result in long output strings...
|
|
286
|
-
coder.encode_hex("9a566b8b-8618-42ab-8db7-a5a0276401fd")
|
|
287
|
-
# => "5jjy-c8d9-hxp2-qsve-rgh9-rxnt-7nb5-tve7-bf84-vr"
|
|
288
|
-
#
|
|
289
|
-
# but there is an option to help reduce this...
|
|
290
|
-
coder = ::EncodedId::ReversibleId.new(salt: my_salt, hex_digit_encoding_group_size: 32)
|
|
291
|
-
coder.encode_hex("9a566b8b-8618-42ab-8db7-a5a0276401fd")
|
|
292
|
-
# => "vr7m-qra8-m5y6-dkgj-5rqr-q44e-gp4a-52"
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### `EncodedId::ReversibleId#decode_hex`
|
|
296
|
-
|
|
297
|
-
`decode_hex(encoded_id)` , where the output is an array of hex strings.
|
|
106
|
+
Visit [encoded-id.onrender.com](https://encoded-id.onrender.com) for comprehensive documentation including:
|
|
298
107
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
108
|
+
- [EncodedId Core API](https://encoded-id.onrender.com/docs/encoded_id/api)
|
|
109
|
+
- [Rails Integration API](https://encoded-id.onrender.com/docs/encoded_id_rails/api)
|
|
110
|
+
- [Configuration Options](https://encoded-id.onrender.com/docs/encoded_id/configuration)
|
|
111
|
+
- [Examples](https://encoded-id.onrender.com/docs/encoded_id/examples)
|
|
112
|
+
- [Advanced Topics](https://encoded-id.onrender.com/docs/advanced-topics)
|
|
303
113
|
|
|
304
114
|
## Development
|
|
305
115
|
|
|
306
|
-
After checking out the repo, run `bin/setup` to install dependencies.
|
|
307
|
-
|
|
308
|
-
Run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
309
|
-
|
|
310
|
-
### Running tests
|
|
116
|
+
After checking out the repo, run `bin/setup` to install dependencies. Run `bundle exec rake test` to run the tests.
|
|
311
117
|
|
|
312
|
-
Run `
|
|
313
|
-
|
|
314
|
-
### Type check
|
|
315
|
-
|
|
316
|
-
First install RBS dependencies:
|
|
317
|
-
|
|
318
|
-
```bash
|
|
319
|
-
rbs collection install
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
Then run:
|
|
323
|
-
|
|
324
|
-
```bash
|
|
325
|
-
steep check
|
|
326
|
-
```
|
|
118
|
+
Run benchmarks with `bin/benchmark <type>` where type is one of: `ips`, `memory`, `comparison`, `profile`, `flamegraph`, or `stress_decode`.
|
|
327
119
|
|
|
328
|
-
|
|
120
|
+
### Documentation
|
|
329
121
|
|
|
330
|
-
|
|
331
|
-
- https://www.crockford.com/base32.html
|
|
122
|
+
Run `bundle exec rake website:build` to build or `bundle exec rake website:serve` to preview locally.
|
|
332
123
|
|
|
333
124
|
## Contributing
|
|
334
125
|
|
|
@@ -336,49 +127,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/steveg
|
|
|
336
127
|
|
|
337
128
|
## License
|
|
338
129
|
|
|
339
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
340
|
-
|
|
341
|
-
## Custom HashId Implementation
|
|
342
|
-
|
|
343
|
-
Internally, `encoded_id` uses its own HashId implementation (`EncodedId::HashId`) instead of the original `hashids` gem. This custom implementation was created to improve both performance and memory usage.
|
|
344
|
-
|
|
345
|
-
Recent benchmarks show significant improvements:
|
|
346
|
-
|
|
347
|
-
### Performance Comparison
|
|
348
|
-
|
|
349
|
-
```
|
|
350
|
-
| Test | Hashids (i/s) | EncodedId::HashId (i/s) | Speedup |
|
|
351
|
-
| ------------------------- | ------------ | --------------------- | ------- |
|
|
352
|
-
| #encode - 1 ID | 131,000.979 | 197,586.231 | 1.51x |
|
|
353
|
-
| #decode - 1 ID | 65,791.334 | 92,425.571 | 1.40x |
|
|
354
|
-
| #encode - 10 IDs | 13,773.355 | 20,669.715 | 1.50x |
|
|
355
|
-
| #decode - 10 IDs | 6,911.872 | 9,990.078 | 1.45x |
|
|
356
|
-
| #encode w YJIT - 1 ID | 265,764.969 | 877,551.362 | 3.30x |
|
|
357
|
-
| #decode w YJIT - 1 ID | 130,154.837 | 348,000.817 | 2.67x |
|
|
358
|
-
| #encode w YJIT - 10 IDs | 27,966.457 | 100,461.237 | 3.59x |
|
|
359
|
-
| #decode w YJIT - 10 IDs | 14,187.346 | 43,974.011 | 3.10x |
|
|
360
|
-
| #encode w YJIT - 1000 IDs | 268.140 | 1,077.855 | 4.02x |
|
|
361
|
-
| #decode w YJIT - 1000 IDs | 136.217 | 464.579 | 3.41x |
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
With YJIT enabled, the performance improvements are even more significant, with up to 4x faster operation for large inputs.
|
|
365
|
-
|
|
366
|
-
### Memory Usage Comparison
|
|
367
|
-
|
|
368
|
-
```
|
|
369
|
-
| Test | Implementation | Allocated Memory | Allocated Objects | Memory Reduction |
|
|
370
|
-
| ------------------- | ---------------- | ---------------- | ----------------- | ---------------- |
|
|
371
|
-
| encode small input | Hashids | 7.28 KB | 120 | - |
|
|
372
|
-
| | EncodedId::HashId | 920 B | 6 | 87.66% |
|
|
373
|
-
| encode large input | Hashids | 403.36 KB | 5998 | - |
|
|
374
|
-
| | EncodedId::HashId | 8.36 KB | 104 | 97.93% |
|
|
375
|
-
| decode large input | Hashids | 366.88 KB | 5761 | - |
|
|
376
|
-
| | EncodedId::HashId | 14.63 KB | 264 | 96.01% |
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
The memory usage improvements are dramatic, with up to 98% reduction in memory allocation for large inputs.
|
|
380
|
-
|
|
381
|
-
Run `bin/are_we_fast_yet` and `bin/memory_profile` in your environment to see the current performance difference.
|
|
382
|
-
|
|
383
|
-
## keywords
|
|
384
|
-
hash ID, friendly ID, obfuscate ID, rails, ActiveRecord, model, slug, vanity URL, friendly URL
|
|
130
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|