encoded_id 1.0.0.rc5 → 1.0.0.rc7

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +99 -3
  3. data/README.md +86 -329
  4. data/context/encoded_id.md +437 -0
  5. data/lib/encoded_id/alphabet.rb +34 -3
  6. data/lib/encoded_id/blocklist.rb +100 -0
  7. data/lib/encoded_id/encoders/base_configuration.rb +154 -0
  8. data/lib/encoded_id/encoders/hashid.rb +527 -0
  9. data/lib/encoded_id/encoders/hashid_configuration.rb +40 -0
  10. data/lib/encoded_id/encoders/hashid_consistent_shuffle.rb +110 -0
  11. data/lib/encoded_id/encoders/hashid_ordinal_alphabet_separator_guards.rb +244 -0
  12. data/lib/encoded_id/encoders/hashid_salt.rb +51 -0
  13. data/lib/encoded_id/encoders/my_sqids.rb +454 -0
  14. data/lib/encoded_id/encoders/sqids.rb +59 -0
  15. data/lib/encoded_id/encoders/sqids_configuration.rb +22 -0
  16. data/lib/encoded_id/encoders/sqids_with_blocklist_mode.rb +54 -0
  17. data/lib/encoded_id/hex_representation.rb +29 -14
  18. data/lib/encoded_id/reversible_id.rb +115 -82
  19. data/lib/encoded_id/version.rb +3 -1
  20. data/lib/encoded_id.rb +34 -4
  21. metadata +34 -26
  22. data/.devcontainer/Dockerfile +0 -9
  23. data/.devcontainer/compose.yml +0 -8
  24. data/.devcontainer/devcontainer.json +0 -8
  25. data/.standard.yml +0 -2
  26. data/Gemfile +0 -36
  27. data/Rakefile +0 -20
  28. data/Steepfile +0 -5
  29. data/ext/encoded_id/extconf.rb +0 -3
  30. data/ext/encoded_id/extension.c +0 -123
  31. data/ext/encoded_id/hashids.c +0 -939
  32. data/ext/encoded_id/hashids.h +0 -139
  33. data/lib/encoded_id/hash_id.rb +0 -227
  34. data/lib/encoded_id/hash_id_consistent_shuffle.rb +0 -27
  35. data/lib/encoded_id/hash_id_salt.rb +0 -15
  36. data/lib/encoded_id/ordinal_alphabet_separator_guards.rb +0 -90
  37. data/rbs_collection.yaml +0 -24
  38. data/sig/encoded_id.rbs +0 -189
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b93ebfafa557cd45d9158fa850a474cb3f56de3255b650aeed11bbc131b67ed2
4
- data.tar.gz: a3a9feb5004a637c6190ea3d969e03de6066d3b94e7b9b54d8be1c639b8b17af
3
+ metadata.gz: c94c4fae6354b78328fed94361c666d7df2cf7e797cd1523db2db6e7a57e3d81
4
+ data.tar.gz: d65c032660d6894da1c81bec5156a9f733ea02d56631b6cc199ed82dcdd1eb24
5
5
  SHA512:
6
- metadata.gz: 3f06797187a84df0d6436868d82d9d096220e88e9087bad13a78cc766e09681ffdd1db73daa7f9af90288e988b0e4034881b1fc0f7c9129bc6b64a9b8e332589
7
- data.tar.gz: 764f505dfb1209bb358784906cfc648bdfee6cf58d79fb5872105d1234ff2839d072b3e899176f4e765f69caccabc00d9d105c9bf484ce2ccf170fdc594c7f44
6
+ metadata.gz: 6c6a510d660bc34709dc4442dcfd14d63320b79b79f595de8dea225d21379cd859d7473ecab83e137c557fca0f3bf3ceaf0c3074efe98434c5743bb3d0d8387a
7
+ data.tar.gz: f7724cf6109b4dfd25729bf7c974c496864525e46de58141bba0bf74ae69ce165d8c6549a6a0ab23325dd0c0fbd6386d40815573be3cfc5ca59dd3fa50a83dc6
data/CHANGELOG.md CHANGED
@@ -1,12 +1,67 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [2.0.0.alpha1] - unreleased
3
+ - nothing yet
4
+
5
+ ## [1.0.0] - unreleased
6
+
7
+ - First stable release!
8
+
9
+ **Important!!: `:sqids` are not compatible with `:hashids`, DO NOT CHANGE FROM ONE TO THE OTHER AFTER GOING LIVE.**
10
+
11
+ ## [1.0.0.rc7] - 2025-11-19
4
12
 
5
13
  ### Breaking changes
6
14
 
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. Generation of the encoded ID is 1.5 times faster and uses less memory.
15
+ - `ReversibleId` now no longer downcases the encodedid input string by default on decode, ie the `decode` option `downcase` is now `false`. This can be configured via the Rails configuration `downcase_on_decode` option. In a future release the `downcase` option will be removed.
16
+ - The default encoding engine is now `:sqids` to reflect the official "deprecated" status of `Hashid`s (see https://sqids.org/faq#why-hashids)
17
+ - Ruby < 3.2 support dropped. The minimum supported Ruby version is now 3.2.0
18
+ - `Encoders` classes no longer expose `encode_hex` and `decode_hex` as they worked differently to the similarly named methods on ReversibleId
19
+ - Rails generator now needs you to specify which encoding algorithm you are using
8
20
 
9
- ## [1.0.0] - unreleased
21
+ ### Added (Rails integration)
22
+
23
+ - `encoded_id_options` class method to override `encoded_id` configuration on a model by model basis
24
+ - Blocklist application "modes". User can decide if the blocklist checks should be applied in situations
25
+ where very long encoded IDs are likely and hence block word collisions are undesirably likely.
26
+
27
+ ### Changed
28
+
29
+ - Blocklists are now pre-filtered to the encoder alphabet to avoid testing words which cannot be created by that alphabet anyway.
30
+ - Updates to inline RBS type signatures
31
+ - Documentation updates
32
+
33
+ ## [1.0.0.rc6] - 2025-11-17
34
+
35
+ ### Breaking changes
36
+
37
+ - Empty array inputs will now raise `InvalidInputError`
38
+
39
+ ### Added
40
+
41
+ - Added support for [Sqids](https://sqids.org) as an alternative ID encoding engine. The default remains HashIds for backward compatibility.
42
+ - New encoder abstraction layer allows switching between HashIds and Sqids via the `encoder: :sqids` or `encoder: :hashids` parameter to `ReversibleId.new`.
43
+ - 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.
44
+
45
+ ### Added (Rails integration)
46
+
47
+ - Merged `encoded_id-rails` gem into the monorepo
48
+ - Support for configuring the encoder and blocklist options in Rails through the configuration class
49
+ - `#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.
50
+ - New `EncodedId::Rails::Persists` module which adds hooks to the model to persist the encoded ID to the DB (see docs).
51
+ - `#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`.
52
+ - `.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.
53
+ - `.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.
54
+ - `Configuration#model_to_param_returns_encoded_id` to allow `EncodedId::Rails::Model` inclusion to also bring in `EncodedId::Rails::PathParam` automatically.
55
+
56
+ ### Changed (Rails integration)
57
+
58
+ - `#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.
59
+ - `#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.
60
+
61
+ ### Fixed (Rails integration)
62
+
63
+ - `#decode_encoded_id` now raises if the encoded ID is not a string.
64
+ - Handle more cases where a record held onto a memoized `encoded_id` even though its `id` had changed
10
65
 
11
66
  ## [1.0.0.rc5] - 2025-04-09
12
67
 
@@ -48,3 +103,44 @@
48
103
  ## [0.1.0] - 2022-10-11
49
104
 
50
105
  - Initial release
106
+
107
+ ## Rails Integration History
108
+
109
+ ## [0.6.2] - 2023-02-09
110
+
111
+ - Fix `encoded_id` memoization clearing when record is duplicated
112
+
113
+ ## [0.6.1] - 2023-02-09
114
+
115
+ - Fix `#encoded_id` to return nil if `#id` is nil
116
+ - Ensure `encoded_id` memoization is cleared when record is duplicated, or id changes
117
+
118
+ ## [0.6.0] - 2022-12-21
119
+
120
+ - Rename mixin to `Model`
121
+ - Introduce optional mixins for overriding `#to_param`
122
+
123
+ ## [0.5.0] - 2022-12-21
124
+
125
+ - `name_for_encoded_id_slug` no longer uses the return value from name but rather just uses the `class` `name`.
126
+ - If you want to change the name used in the slug, override `name_for_encoded_id_slug`
127
+
128
+ ## [0.4.0] - 2022-12-18
129
+
130
+ - Refactor internals, remove any methods not actually related to creating `encoded_id`, (eg `slugged_id` was removed).
131
+
132
+ ## [0.3.1] - 2022-12-15
133
+
134
+ - Fix default config
135
+
136
+ ## [0.3.0] - 2022-12-15
137
+
138
+ - Updates gem `encoded_id` dependency and fixes configuration
139
+
140
+ ## [0.2.0] - 2022-12-14
141
+
142
+ - No notes...
143
+
144
+ ## [0.1.0] - 2022-11-17
145
+
146
+ - Initial release of Rails integration
data/README.md CHANGED
@@ -1,334 +1,136 @@
1
- # EncodedId
1
+ # EncodedId and EncodedId::Rails
2
2
 
3
- Encode numerical or hex IDs into obfuscated strings that can be used in URLs.
3
+ ![Coverage](badges/coverage_badge_total.svg)
4
+ ![RubyCritic](badges/rubycritic_badge_score.svg)
4
5
 
5
- ```ruby
6
- coder = ::EncodedId::ReversibleId.new(salt: my_salt)
7
- coder.encode(123)
8
- # => "p5w9-z27j"
9
- coder.encode_hex("10f8c")
10
- # => "w72a-y0az"
11
- ```
12
-
13
- The obfuscated strings are reversible (they decode them back into the original IDs).
14
-
15
- Also supports encoding multiple IDs at once.
16
-
17
- ```ruby
18
- my_salt = "salt!"
19
- coder = ::EncodedId::ReversibleId.new(salt: my_salt)
20
-
21
- # One of more values can be encoded
22
- coder.encode([78, 45])
23
- # => "z2j7-0dmw"
24
-
25
- # The encoded string can then be reversed back into the original IDs
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
66
- class User < ApplicationRecord
67
- include EncodedId::WithEncodedId
68
- end
69
-
70
- User.find_by_encoded_id("p5w9-z27j")
71
- # => #<User id: 78>
72
- ```
73
-
74
- ### Note on security of encoded IDs (hashids)
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/
80
-
81
- ## Compare to alternate Gems
82
-
83
- - https://github.com/excid3/prefixed_ids
84
- - https://github.com/namick/obfuscate_id
85
- - https://github.com/norman/friendly_id
86
- - https://github.com/SPBTV/with_uid
87
-
88
- ## Installation
89
-
90
- Install the gem and add to the application's Gemfile by executing:
91
-
92
- $ bundle add encoded_id
93
-
94
- If bundler is not being used to manage dependencies, install the gem by executing:
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).
6
+ `encoded_id` lets you encode numerical or hex IDs into obfuscated strings that can be used in URLs.
155
7
 
156
- `alphabet` must be an instance of `EncodedId::Alphabet`.
8
+ `encoded_id-rails` is a Rails integration that provides additional features for using `encoded_id` with ActiveRecord models.
157
9
 
158
- The default alphabet is `EncodedId::Alphabet.modified_crockford`.
10
+ It's one of the most, if not _the_ most, feature complete gem of its kind!
159
11
 
160
- To create a new alphabet, use `EncodedId::Alphabet.new`:
12
+ 👉 **Full documentation available at [encoded-id.onrender.com](https://encoded-id.onrender.com)**
161
13
 
162
- ```ruby
163
- alphabet = EncodedId::Alphabet.new("0123456789abcdef")
164
- ```
14
+ ## Key Features
165
15
 
166
- `EncodedId::Alphabet.new(characters, equivalences)`
16
+ * 🔄 **Reversible** - Encoded IDs can be decoded back to the original values
17
+ * 👥 **Multiple IDs** - Encode multiple numeric IDs in one string
18
+ * 🚀 **Choose your encoding** - Supports `Sqids` (default) and `Hashids`, or use your own custom encoder
19
+ * 👓 **Human-readable** - Character grouping & character mappings of easily confused characters for better readability
20
+ * 🔡 **Custom alphabets** - Use your preferred character set, or a provided default
21
+ * 🚗 **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
22
+ * 🤬 **Blocklist filtering** - Built-in word blocklist support with configurable modes and optional default lists
167
23
 
168
- **characters**
24
+ ### Rails Integration Features
169
25
 
170
- `characters`: the characters of the alphabet. Can be a string or array of strings.
26
+ * 🏷️ **ActiveRecord integration** - Use with ActiveRecord models
27
+ * 🔑 **Per-model configuration** - Use custom salt and encoding settings per model
28
+ * 💅 **Slugged IDs** - URL-friendly slugs like `my-product--p5w9-z27j`
29
+ * 🔖 **Annotated IDs** - Model type indicators like `user_p5w9-z27j` (default behavior)
30
+ * 🔍 **Finder methods** - `find_by_encoded_id`, `find_by_encoded_id!`, `find_all_by_encoded_id`, `where_encoded_id`
31
+ * 🛣️ **URL params** - `to_param` automatically uses encoded IDs
32
+ * 🔒 **Safe defaults** - Limits on encoded ID lengths to prevent CPU and memory-intensive encode/decodes when used in URLs
33
+ * 💾 **Persistence** - Optional database persistence for efficient lookups
171
34
 
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
35
 
36
+ ## Quick Example
175
37
 
176
38
  ```ruby
177
- alphabet = EncodedId::Alphabet.new("ςερτυθιοπλκξηγφδσαζχψωβνμ")
178
- coder = ::EncodedId::ReversibleId.new(salt: my_salt, alphabet: alphabet)
39
+ # Using Hashids encoder (requires salt)
40
+ coder = ::EncodedId::ReversibleId.hashid(salt: "my-salt")
179
41
  coder.encode(123)
180
- # => "πφλχ-ψησω"
181
- ```
182
-
183
- Note that larger alphabets can result in shorter encoded strings (but remember that `length` specifies the minimum length
184
- of the encoded string).
42
+ # => "m3pm-8anj"
185
43
 
186
- **equivalences**
44
+ # The encoded strings are reversible
45
+ coder.decode("m3pm-8anj")
46
+ # => [123]
187
47
 
188
- You can optionally pass an appropriate character `equivalences` mapping. This is used to map easily confused characters
189
- to their counterpart.
48
+ # Supports encoding multiple IDs at once
49
+ coder.encode([78, 45])
50
+ # => "ny9y-sd7p"
190
51
 
191
- `equivalences`: a hash of characters keys, with their equivalent alphabet character mapped to in the values.
52
+ # Using Sqids encoder (default, no salt required)
53
+ sqids_coder = ::EncodedId::ReversibleId.sqids
54
+ sqids_coder.encode(123)
55
+ # => (encoded value varies)
192
56
 
193
- Note that the characters to be mapped:
194
- - must not be in the alphabet,
195
- - must map to a character that is in the alphabet.
57
+ # Can also be used with ActiveRecord models
58
+ class User < ApplicationRecord
59
+ include EncodedId::Rails::Model
196
60
 
197
- `nil` is the default value which means no equivalences are used.
61
+ # Optional: define method to provide slug for encoded ID
62
+ def name_for_encoded_id_slug
63
+ full_name
64
+ end
65
+ end
198
66
 
199
- ```ruby
200
- alphabet = EncodedId::Alphabet.new("!@#$%^&*()+-={}", {"_" => "-"})
201
- coder = ::EncodedId::ReversibleId.new(salt: my_salt, alphabet: alphabet)
202
- coder.encode(123)
203
- # => "}*^(-^}*="
67
+ # Find by encoded ID
68
+ user = User.find_by_encoded_id("p5w9-z27j") # => #<User id: 78>
69
+ user.encoded_id # => "user_p5w9-z27j"
70
+ user.slugged_encoded_id # => "bob-smith--user_p5w9-z27j"
204
71
  ```
205
72
 
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**
73
+ ## Standalone Gem
219
74
 
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
75
 
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"
76
+ ```bash
77
+ # Add to Gemfile
78
+ bundle add encoded_id
238
79
 
239
- # One of more values can be encoded
240
- coder.encode([78, 45])
241
- # => "z2j7-0dmw"
80
+ # Or install directly
81
+ gem install encoded_id
242
82
  ```
243
83
 
244
- ## `EncodedId::ReversibleId#decode`
245
-
246
- `#decode(encoded_id)`: where `encoded_id` is a string to decode.
84
+ See the [EncodedId API](https://encoded-id.onrender.com/docs/encoded_id/api) documentation for more details.
247
85
 
248
- ```ruby
249
- # The encoded string can then be reversed back into the original IDs
250
- coder.decode("z2j7-0dmw")
251
- # => [78, 45]
252
- ```
86
+ ## Rails Integration Gem
253
87
 
254
- ## Using with hex strings
255
-
256
- **Experimental** (subject to incompatible changes in future versions)
88
+ ```bash
89
+ # Add to Gemfile
90
+ bundle add encoded_id-rails
257
91
 
258
- ```ruby
259
- # Hex input strings are also supported
260
- coder.encode_hex("10f8c")
261
- # => "w72a-y0az"
92
+ # Then run the generator
93
+ rails g encoded_id:rails:install
262
94
  ```
263
95
 
264
- When encoding hex strings, the input is split into groups of hex digits, and each group is encoded separately as its
265
- integer equivalent. In other words the input is converted into an array of integers and encoded as normal with the
266
- `encode` method.
96
+ See the [Rails Integration](https://encoded-id.onrender.com/docs/encoded_id_rails) documentation for more details.
267
97
 
268
- eg with `hex_digit_encoding_group_size=1` and inpu `f1`, is split into `f` and `1`, and then encoded as `15` and `1`
269
- respectively, ie `encode` is called with `[15, 1]`.
98
+ ## Security Note
270
99
 
271
- To encode multiple hex inputs the encoded string contains markers to indicate the start of a new hex input. This
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)`).
100
+ **Encoded IDs are not secure**. They are meant to provide obfuscation, not encryption. Do not use them as a security mechanism.
274
101
 
275
- So for a hex digit encoding group size of 4 (ie group max value is `0xFFFF`), the marker is `65536`
102
+ As of version 1.0.0, `Sqids` is the default encoder. `Hashids` is still supported but is officially deprecated by the Hashids project in favor of Sqids.
276
103
 
277
- For example with `hex_digit_encoding_group_size=1` for the inputs `f1` and `e2` encoded together, the
278
- actual encoded integer array is `[15, 1, 16, 14, 2]`.
104
+ Read more about the security implications: [Hashids expose salt value](https://www.sjoerdlangkemper.nl/2023/11/25/hashids-expose-salt-value/) (note: this specifically applies to Hashids encoder)
279
105
 
280
- ### `EncodedId::ReversibleId#encode_hex`
106
+ ## Compare to Alternate Gems
281
107
 
282
- `encode_hex(hex_string)` , where `hex_string` is a string of hex digits or an array of hex strings.
108
+ - [prefixed_ids](https://github.com/excid3/prefixed_ids)
109
+ - [obfuscate_id](https://github.com/namick/obfuscate_id)
110
+ - [friendly_id](https://github.com/norman/friendly_id)
111
+ - [with_uid](https://github.com/SPBTV/with_uid)
112
+ - [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)
283
113
 
284
- ```ruby
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
- ```
114
+ For a detailed comparison, see the [Compared to Other Gems](https://encoded-id.onrender.com/docs/compared-to) documentation page.
294
115
 
295
- ### `EncodedId::ReversibleId#decode_hex`
116
+ ## Documentation
296
117
 
297
- `decode_hex(encoded_id)` , where the output is an array of hex strings.
118
+ Visit [encoded-id.onrender.com](https://encoded-id.onrender.com) for comprehensive documentation including:
298
119
 
299
- ```ruby
300
- coder.decode_hex("5jjy-c8d9-hxp2-qsve-rgh9-rxnt-7nb5-tve7-bf84-vr")
301
- # => ["9a566b8b-8618-42ab-8db7-a5a0276401fd"]
302
- ```
120
+ - [EncodedId Core Guide](https://encoded-id.onrender.com/docs/encoded_id/) - Installation, configuration, examples, and advanced topics
121
+ - [EncodedId Rails Guide](https://encoded-id.onrender.com/docs/encoded_id_rails/) - Rails integration, configuration, and examples
122
+ - [EncodedId Core API Reference](https://encoded-id.onrender.com/docs/encoded_id/api)
123
+ - [Rails Integration API Reference](https://encoded-id.onrender.com/docs/encoded_id_rails/api)
303
124
 
304
125
  ## Development
305
126
 
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
311
-
312
- Run `bundle exec rake test` to run the tests.
313
-
314
- ### Type check
127
+ After checking out the repo, run `bin/setup` to install dependencies. Run `bundle exec rake test` to run the tests.
315
128
 
316
- First install RBS dependencies:
317
-
318
- ```bash
319
- rbs collection install
320
- ```
321
-
322
- Then run:
323
-
324
- ```bash
325
- steep check
326
- ```
129
+ Run benchmarks with `bin/benchmark <type>` where type is one of: `ips`, `memory`, `comparison`, `profile`, `flamegraph`, or `stress_decode`.
327
130
 
328
- ## See also
131
+ ### Documentation
329
132
 
330
- - https://hashids.org
331
- - https://www.crockford.com/base32.html
133
+ Run `bundle exec rake website:build` to build or `bundle exec rake website:serve` to preview locally.
332
134
 
333
135
  ## Contributing
334
136
 
@@ -336,49 +138,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/steveg
336
138
 
337
139
  ## License
338
140
 
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
141
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).