opaque_id 1.2.0 → 1.4.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 +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +48 -0
- data/CODE_OF_CONDUCT.md +11 -11
- data/README.md +82 -0
- data/docs/.gitignore +5 -0
- data/docs/404.html +25 -0
- data/docs/Gemfile +31 -0
- data/docs/Gemfile.lock +335 -0
- data/docs/_config.yml +151 -0
- data/docs/_data/navigation.yml +132 -0
- data/docs/_includes/footer_custom.html +8 -0
- data/docs/_includes/head_custom.html +67 -0
- data/docs/algorithms.md +412 -0
- data/docs/alphabets.md +524 -0
- data/docs/api-reference.md +597 -0
- data/docs/assets/css/custom.scss +751 -0
- data/docs/assets/images/favicon.svg +17 -0
- data/docs/assets/images/og-image.svg +65 -0
- data/docs/configuration.md +551 -0
- data/docs/development.md +570 -0
- data/docs/getting-started.md +259 -0
- data/docs/index.md +135 -0
- data/docs/installation.md +380 -0
- data/docs/performance.md +491 -0
- data/docs/robots.txt +11 -0
- data/docs/security.md +601 -0
- data/docs/usage.md +417 -0
- data/docs/use-cases.md +572 -0
- data/lib/opaque_id/version.rb +1 -1
- data/tasks/0003-prd-documentation-site.md +191 -0
- data/tasks/tasks-0003-prd-documentation-site.md +84 -0
- metadata +27 -2
- data/sig/opaque_id.rbs +0 -4
@@ -0,0 +1,597 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: API Reference
|
4
|
+
nav_order: 12
|
5
|
+
description: "Complete API documentation for OpaqueId methods and classes"
|
6
|
+
permalink: /api-reference/
|
7
|
+
---
|
8
|
+
|
9
|
+
# API Reference
|
10
|
+
|
11
|
+
This document provides complete API documentation for OpaqueId, including all methods, classes, and configuration options.
|
12
|
+
|
13
|
+
- TOC
|
14
|
+
{:toc}
|
15
|
+
|
16
|
+
## Core Module: OpaqueId
|
17
|
+
|
18
|
+
The main module for generating opaque IDs.
|
19
|
+
|
20
|
+
### Constants
|
21
|
+
|
22
|
+
#### ALPHANUMERIC_ALPHABET
|
23
|
+
|
24
|
+
Default alphabet for ID generation.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
OpaqueId::ALPHANUMERIC_ALPHABET
|
28
|
+
# => "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
29
|
+
```
|
30
|
+
|
31
|
+
**Characteristics:**
|
32
|
+
|
33
|
+
- **Length**: 62 characters
|
34
|
+
- **Characters**: A-Z, a-z, 0-9
|
35
|
+
- **Use case**: General purpose, URL-safe
|
36
|
+
- **Performance**: Good
|
37
|
+
|
38
|
+
#### STANDARD_ALPHABET
|
39
|
+
|
40
|
+
Standard alphabet for high-performance generation.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
OpaqueId::STANDARD_ALPHABET
|
44
|
+
# => "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
45
|
+
```
|
46
|
+
|
47
|
+
**Characteristics:**
|
48
|
+
|
49
|
+
- **Length**: 64 characters
|
50
|
+
- **Characters**: A-Z, a-z, 0-9, -, \_
|
51
|
+
- **Use case**: High performance, URL-safe
|
52
|
+
- **Performance**: Best (optimized path)
|
53
|
+
|
54
|
+
### Methods
|
55
|
+
|
56
|
+
#### generate
|
57
|
+
|
58
|
+
Generates a cryptographically secure opaque ID.
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
OpaqueId.generate(size: 21, alphabet: ALPHANUMERIC_ALPHABET)
|
62
|
+
```
|
63
|
+
|
64
|
+
**Parameters:**
|
65
|
+
|
66
|
+
| Parameter | Type | Default | Description |
|
67
|
+
| ---------- | ------- | ----------------------- | ---------------------------- |
|
68
|
+
| `size` | Integer | `21` | Length of the generated ID |
|
69
|
+
| `alphabet` | String | `ALPHANUMERIC_ALPHABET` | Character set for generation |
|
70
|
+
|
71
|
+
**Returns:** `String` - The generated opaque ID
|
72
|
+
|
73
|
+
**Raises:**
|
74
|
+
|
75
|
+
- `ConfigurationError` - If size is not positive or alphabet is empty
|
76
|
+
- `GenerationError` - If ID generation fails
|
77
|
+
|
78
|
+
**Examples:**
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
# Generate with default parameters
|
82
|
+
id = OpaqueId.generate
|
83
|
+
# => "V1StGXR8_Z5jdHi6B-myT"
|
84
|
+
|
85
|
+
# Generate with custom length
|
86
|
+
id = OpaqueId.generate(size: 10)
|
87
|
+
# => "V1StGXR8_Z5"
|
88
|
+
|
89
|
+
# Generate with custom alphabet
|
90
|
+
id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
|
91
|
+
# => "V1StGXR8_Z5jdHi6B-myT"
|
92
|
+
|
93
|
+
# Generate with both custom parameters
|
94
|
+
id = OpaqueId.generate(size: 15, alphabet: "0123456789")
|
95
|
+
# => "123456789012345"
|
96
|
+
```
|
97
|
+
|
98
|
+
**Algorithm Selection:**
|
99
|
+
|
100
|
+
- **Fast Path**: Used for 64-character alphabets (bitwise optimization)
|
101
|
+
- **Unbiased Path**: Used for other alphabets (rejection sampling)
|
102
|
+
- **Direct Repetition**: Used for single-character alphabets
|
103
|
+
|
104
|
+
## ActiveRecord Concern: OpaqueId::Model
|
105
|
+
|
106
|
+
Provides ActiveRecord integration for automatic opaque ID generation.
|
107
|
+
|
108
|
+
### Class Methods
|
109
|
+
|
110
|
+
#### opaque_id_column
|
111
|
+
|
112
|
+
Gets or sets the column name for storing opaque IDs.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
self.opaque_id_column = :public_id
|
116
|
+
opaque_id_column
|
117
|
+
# => :public_id
|
118
|
+
```
|
119
|
+
|
120
|
+
**Default:** `:opaque_id`
|
121
|
+
|
122
|
+
**Returns:** `Symbol` - The column name
|
123
|
+
|
124
|
+
#### opaque_id_length
|
125
|
+
|
126
|
+
Gets or sets the length of generated opaque IDs.
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
self.opaque_id_length = 15
|
130
|
+
opaque_id_length
|
131
|
+
# => 15
|
132
|
+
```
|
133
|
+
|
134
|
+
**Default:** `21`
|
135
|
+
|
136
|
+
**Returns:** `Integer` - The ID length
|
137
|
+
|
138
|
+
#### opaque_id_alphabet
|
139
|
+
|
140
|
+
Gets or sets the alphabet for ID generation.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
|
144
|
+
opaque_id_alphabet
|
145
|
+
# => "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
146
|
+
```
|
147
|
+
|
148
|
+
**Default:** `OpaqueId::ALPHANUMERIC_ALPHABET`
|
149
|
+
|
150
|
+
**Returns:** `String` - The alphabet
|
151
|
+
|
152
|
+
#### opaque_id_require_letter_start
|
153
|
+
|
154
|
+
Gets or sets whether IDs must start with a letter.
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
self.opaque_id_require_letter_start = true
|
158
|
+
opaque_id_require_letter_start
|
159
|
+
# => true
|
160
|
+
```
|
161
|
+
|
162
|
+
**Default:** `false`
|
163
|
+
|
164
|
+
**Returns:** `Boolean` - Whether letter start is required
|
165
|
+
|
166
|
+
#### opaque_id_max_retry
|
167
|
+
|
168
|
+
Gets or sets the maximum retry attempts for collision handling.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
self.opaque_id_max_retry = 5
|
172
|
+
opaque_id_max_retry
|
173
|
+
# => 5
|
174
|
+
```
|
175
|
+
|
176
|
+
**Default:** `3`
|
177
|
+
|
178
|
+
**Returns:** `Integer` - Maximum retry attempts
|
179
|
+
|
180
|
+
#### opaque_id_purge_chars
|
181
|
+
|
182
|
+
Gets or sets characters to exclude from generated IDs.
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
self.opaque_id_purge_chars = ['0', 'O', 'l', 'I']
|
186
|
+
opaque_id_purge_chars
|
187
|
+
# => ['0', 'O', 'l', 'I']
|
188
|
+
```
|
189
|
+
|
190
|
+
**Default:** `[]`
|
191
|
+
|
192
|
+
**Returns:** `Array<String>` - Characters to exclude
|
193
|
+
|
194
|
+
#### find_by_opaque_id
|
195
|
+
|
196
|
+
Finds a record by its opaque ID.
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
User.find_by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
|
200
|
+
```
|
201
|
+
|
202
|
+
**Parameters:**
|
203
|
+
|
204
|
+
| Parameter | Type | Description |
|
205
|
+
| ----------- | ------ | --------------------------- |
|
206
|
+
| `opaque_id` | String | The opaque ID to search for |
|
207
|
+
|
208
|
+
**Returns:** `ActiveRecord::Base` or `nil` - The found record or nil
|
209
|
+
|
210
|
+
**Examples:**
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
# Find existing user
|
214
|
+
user = User.find_by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
|
215
|
+
# => #<User id: 1, opaque_id: "V1StGXR8_Z5jdHi6B-myT", ...>
|
216
|
+
|
217
|
+
# Find non-existent user
|
218
|
+
user = User.find_by_opaque_id("nonexistent")
|
219
|
+
# => nil
|
220
|
+
```
|
221
|
+
|
222
|
+
#### find_by_opaque_id!
|
223
|
+
|
224
|
+
Finds a record by its opaque ID, raising an exception if not found.
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
User.find_by_opaque_id!("V1StGXR8_Z5jdHi6B-myT")
|
228
|
+
```
|
229
|
+
|
230
|
+
**Parameters:**
|
231
|
+
|
232
|
+
| Parameter | Type | Description |
|
233
|
+
| ----------- | ------ | --------------------------- |
|
234
|
+
| `opaque_id` | String | The opaque ID to search for |
|
235
|
+
|
236
|
+
**Returns:** `ActiveRecord::Base` - The found record
|
237
|
+
|
238
|
+
**Raises:**
|
239
|
+
|
240
|
+
- `ActiveRecord::RecordNotFound` - If no record is found
|
241
|
+
|
242
|
+
**Examples:**
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
# Find existing user
|
246
|
+
user = User.find_by_opaque_id!("V1StGXR8_Z5jdHi6B-myT")
|
247
|
+
# => #<User id: 1, opaque_id: "V1StGXR8_Z5jdHi6B-myT", ...>
|
248
|
+
|
249
|
+
# Find non-existent user
|
250
|
+
user = User.find_by_opaque_id!("nonexistent")
|
251
|
+
# => ActiveRecord::RecordNotFound: Couldn't find User with opaque_id 'nonexistent'
|
252
|
+
```
|
253
|
+
|
254
|
+
### Instance Methods
|
255
|
+
|
256
|
+
#### opaque_id
|
257
|
+
|
258
|
+
Gets the opaque ID for the record.
|
259
|
+
|
260
|
+
```ruby
|
261
|
+
user.opaque_id
|
262
|
+
# => "V1StGXR8_Z5jdHi6B-myT"
|
263
|
+
```
|
264
|
+
|
265
|
+
**Returns:** `String` - The opaque ID
|
266
|
+
|
267
|
+
### Callbacks
|
268
|
+
|
269
|
+
#### before_create :set_opaque_id
|
270
|
+
|
271
|
+
Automatically generates an opaque ID before creating a record.
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
class User < ApplicationRecord
|
275
|
+
include OpaqueId::Model
|
276
|
+
end
|
277
|
+
|
278
|
+
user = User.new(name: "John Doe")
|
279
|
+
user.save!
|
280
|
+
puts user.opaque_id
|
281
|
+
# => "V1StGXR8_Z5jdHi6B-myT"
|
282
|
+
```
|
283
|
+
|
284
|
+
## Rails Generator: OpaqueId::Generators::InstallGenerator
|
285
|
+
|
286
|
+
Rails generator for setting up OpaqueId in your application.
|
287
|
+
|
288
|
+
### Usage
|
289
|
+
|
290
|
+
```bash
|
291
|
+
rails generate opaque_id:install ModelName [options]
|
292
|
+
```
|
293
|
+
|
294
|
+
### Arguments
|
295
|
+
|
296
|
+
| Argument | Type | Required | Description |
|
297
|
+
| ------------ | ------ | -------- | --------------------------- |
|
298
|
+
| `model_name` | String | Yes | Name of the model to set up |
|
299
|
+
|
300
|
+
### Options
|
301
|
+
|
302
|
+
| Option | Type | Default | Description |
|
303
|
+
| --------------- | ------ | ----------- | ------------------------------------- |
|
304
|
+
| `--column-name` | String | `opaque_id` | Column name for storing the opaque ID |
|
305
|
+
|
306
|
+
### Examples
|
307
|
+
|
308
|
+
```bash
|
309
|
+
# Basic usage
|
310
|
+
rails generate opaque_id:install User
|
311
|
+
|
312
|
+
# Custom column name
|
313
|
+
rails generate opaque_id:install User --column-name=public_id
|
314
|
+
|
315
|
+
# Multiple models
|
316
|
+
rails generate opaque_id:install User
|
317
|
+
rails generate opaque_id:install Post --column-name=slug
|
318
|
+
rails generate opaque_id:install Comment
|
319
|
+
```
|
320
|
+
|
321
|
+
### Generated Files
|
322
|
+
|
323
|
+
#### Migration
|
324
|
+
|
325
|
+
Creates a migration to add the opaque ID column:
|
326
|
+
|
327
|
+
```ruby
|
328
|
+
class AddOpaqueIdToUsers < ActiveRecord::Migration[8.0]
|
329
|
+
def change
|
330
|
+
add_column :users, :opaque_id, :string
|
331
|
+
add_index :users, :opaque_id, unique: true
|
332
|
+
end
|
333
|
+
end
|
334
|
+
```
|
335
|
+
|
336
|
+
#### Model Update
|
337
|
+
|
338
|
+
Updates the model file to include the concern:
|
339
|
+
|
340
|
+
```ruby
|
341
|
+
class User < ApplicationRecord
|
342
|
+
include OpaqueId::Model
|
343
|
+
end
|
344
|
+
```
|
345
|
+
|
346
|
+
With custom column name:
|
347
|
+
|
348
|
+
```ruby
|
349
|
+
class User < ApplicationRecord
|
350
|
+
include OpaqueId::Model
|
351
|
+
self.opaque_id_column = :public_id
|
352
|
+
end
|
353
|
+
```
|
354
|
+
|
355
|
+
## Error Classes
|
356
|
+
|
357
|
+
### OpaqueId::Error
|
358
|
+
|
359
|
+
Base error class for all OpaqueId errors.
|
360
|
+
|
361
|
+
```ruby
|
362
|
+
OpaqueId::Error
|
363
|
+
# => StandardError
|
364
|
+
```
|
365
|
+
|
366
|
+
### OpaqueId::ConfigurationError
|
367
|
+
|
368
|
+
Raised when configuration parameters are invalid.
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
OpaqueId::ConfigurationError
|
372
|
+
# => OpaqueId::Error
|
373
|
+
```
|
374
|
+
|
375
|
+
**Examples:**
|
376
|
+
|
377
|
+
```ruby
|
378
|
+
# Invalid size
|
379
|
+
OpaqueId.generate(size: 0)
|
380
|
+
# => OpaqueId::ConfigurationError: Size must be positive
|
381
|
+
|
382
|
+
# Empty alphabet
|
383
|
+
OpaqueId.generate(alphabet: "")
|
384
|
+
# => OpaqueId::ConfigurationError: Alphabet cannot be empty
|
385
|
+
```
|
386
|
+
|
387
|
+
### OpaqueId::GenerationError
|
388
|
+
|
389
|
+
Raised when ID generation fails.
|
390
|
+
|
391
|
+
```ruby
|
392
|
+
OpaqueId::GenerationError
|
393
|
+
# => OpaqueId::Error
|
394
|
+
```
|
395
|
+
|
396
|
+
**Examples:**
|
397
|
+
|
398
|
+
```ruby
|
399
|
+
# Collision handling failure
|
400
|
+
class User < ApplicationRecord
|
401
|
+
include OpaqueId::Model
|
402
|
+
self.opaque_id_max_retry = 0
|
403
|
+
end
|
404
|
+
|
405
|
+
user = User.create!(name: "John Doe")
|
406
|
+
# => OpaqueId::GenerationError: Failed to generate opaque ID after 0 retries
|
407
|
+
```
|
408
|
+
|
409
|
+
## Configuration Examples
|
410
|
+
|
411
|
+
### Model Configuration
|
412
|
+
|
413
|
+
```ruby
|
414
|
+
class User < ApplicationRecord
|
415
|
+
include OpaqueId::Model
|
416
|
+
|
417
|
+
# Custom column name
|
418
|
+
self.opaque_id_column = :public_id
|
419
|
+
|
420
|
+
# Custom length
|
421
|
+
self.opaque_id_length = 15
|
422
|
+
|
423
|
+
# Custom alphabet
|
424
|
+
self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
|
425
|
+
|
426
|
+
# Require letter start
|
427
|
+
self.opaque_id_require_letter_start = true
|
428
|
+
|
429
|
+
# Max retry attempts
|
430
|
+
self.opaque_id_max_retry = 5
|
431
|
+
|
432
|
+
# Purge characters
|
433
|
+
self.opaque_id_purge_chars = ['0', 'O', 'l', 'I']
|
434
|
+
end
|
435
|
+
```
|
436
|
+
|
437
|
+
### Global Configuration
|
438
|
+
|
439
|
+
```ruby
|
440
|
+
# config/initializers/opaque_id.rb
|
441
|
+
OpaqueId.configure do |config|
|
442
|
+
config.default_length = 15
|
443
|
+
config.default_alphabet = OpaqueId::STANDARD_ALPHABET
|
444
|
+
end
|
445
|
+
```
|
446
|
+
|
447
|
+
## Usage Examples
|
448
|
+
|
449
|
+
### Basic Usage
|
450
|
+
|
451
|
+
```ruby
|
452
|
+
# Generate standalone ID
|
453
|
+
id = OpaqueId.generate
|
454
|
+
# => "V1StGXR8_Z5jdHi6B-myT"
|
455
|
+
|
456
|
+
# Generate with custom parameters
|
457
|
+
id = OpaqueId.generate(size: 10, alphabet: "0123456789")
|
458
|
+
# => "1234567890"
|
459
|
+
```
|
460
|
+
|
461
|
+
### ActiveRecord Integration
|
462
|
+
|
463
|
+
```ruby
|
464
|
+
class User < ApplicationRecord
|
465
|
+
include OpaqueId::Model
|
466
|
+
end
|
467
|
+
|
468
|
+
# Create user with automatic ID generation
|
469
|
+
user = User.create!(name: "John Doe")
|
470
|
+
puts user.opaque_id
|
471
|
+
# => "V1StGXR8_Z5jdHi6B-myT"
|
472
|
+
|
473
|
+
# Find by opaque ID
|
474
|
+
found_user = User.find_by_opaque_id(user.opaque_id)
|
475
|
+
# => #<User id: 1, opaque_id: "V1StGXR8_Z5jdHi6B-myT", ...>
|
476
|
+
```
|
477
|
+
|
478
|
+
### Custom Configuration
|
479
|
+
|
480
|
+
```ruby
|
481
|
+
class Order < ApplicationRecord
|
482
|
+
include OpaqueId::Model
|
483
|
+
|
484
|
+
# Numeric order numbers
|
485
|
+
self.opaque_id_column = :order_number
|
486
|
+
self.opaque_id_length = 8
|
487
|
+
self.opaque_id_alphabet = "0123456789"
|
488
|
+
end
|
489
|
+
|
490
|
+
order = Order.create!(total: 99.99)
|
491
|
+
puts order.order_number
|
492
|
+
# => "12345678"
|
493
|
+
```
|
494
|
+
|
495
|
+
### Error Handling
|
496
|
+
|
497
|
+
```ruby
|
498
|
+
begin
|
499
|
+
user = User.create!(name: "John Doe")
|
500
|
+
rescue OpaqueId::GenerationError => e
|
501
|
+
Rails.logger.error "Failed to generate opaque ID: #{e.message}"
|
502
|
+
# Handle error appropriately
|
503
|
+
end
|
504
|
+
```
|
505
|
+
|
506
|
+
## Performance Considerations
|
507
|
+
|
508
|
+
### Algorithm Selection
|
509
|
+
|
510
|
+
- **64-character alphabets**: Use fast path (bitwise operations)
|
511
|
+
- **Other alphabets**: Use unbiased path (rejection sampling)
|
512
|
+
- **Single-character alphabets**: Use direct repetition
|
513
|
+
|
514
|
+
### Memory Usage
|
515
|
+
|
516
|
+
- **Per ID**: ~50-70 bytes depending on length
|
517
|
+
- **Batch generation**: Linear scaling with count
|
518
|
+
- **Garbage collection**: Minimal impact
|
519
|
+
|
520
|
+
### Generation Speed
|
521
|
+
|
522
|
+
- **Fast Path**: Optimized for 64-character alphabets
|
523
|
+
- **Unbiased Path**: Slightly slower but ensures uniform distribution
|
524
|
+
- **Scaling**: Linear with ID length
|
525
|
+
|
526
|
+
## Security Considerations
|
527
|
+
|
528
|
+
### Entropy
|
529
|
+
|
530
|
+
- **21-character alphanumeric**: 125 bits entropy
|
531
|
+
- **21-character standard**: 126 bits entropy
|
532
|
+
- **15-character hexadecimal**: 60 bits entropy
|
533
|
+
|
534
|
+
### Collision Probability
|
535
|
+
|
536
|
+
- **1M IDs**: 2.3×10⁻¹⁵ probability
|
537
|
+
- **1B IDs**: 2.3×10⁻⁹ probability
|
538
|
+
- **1T IDs**: 2.3×10⁻³ probability
|
539
|
+
|
540
|
+
### Attack Resistance
|
541
|
+
|
542
|
+
- **Brute Force**: Extremely long time (exponential with ID length)
|
543
|
+
- **Timing Attacks**: Constant-time operations
|
544
|
+
- **Statistical Attacks**: Uniform distribution
|
545
|
+
|
546
|
+
## Best Practices
|
547
|
+
|
548
|
+
### 1. Choose Appropriate Configuration
|
549
|
+
|
550
|
+
```ruby
|
551
|
+
# High security
|
552
|
+
self.opaque_id_length = 21
|
553
|
+
self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
|
554
|
+
|
555
|
+
# High performance
|
556
|
+
self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
|
557
|
+
|
558
|
+
# Human readable
|
559
|
+
self.opaque_id_purge_chars = ['0', 'O', 'l', 'I']
|
560
|
+
```
|
561
|
+
|
562
|
+
### 2. Handle Errors Gracefully
|
563
|
+
|
564
|
+
```ruby
|
565
|
+
begin
|
566
|
+
user = User.create!(name: "John Doe")
|
567
|
+
rescue OpaqueId::GenerationError => e
|
568
|
+
# Log error and handle appropriately
|
569
|
+
Rails.logger.error "ID generation failed: #{e.message}"
|
570
|
+
end
|
571
|
+
```
|
572
|
+
|
573
|
+
### 3. Use Appropriate Finder Methods
|
574
|
+
|
575
|
+
```ruby
|
576
|
+
# Optional lookup
|
577
|
+
user = User.find_by_opaque_id(params[:id])
|
578
|
+
|
579
|
+
# Required lookup
|
580
|
+
user = User.find_by_opaque_id!(params[:id])
|
581
|
+
```
|
582
|
+
|
583
|
+
### 4. Implement Proper Indexing
|
584
|
+
|
585
|
+
```ruby
|
586
|
+
# Ensure database indexes
|
587
|
+
add_index :users, :opaque_id, unique: true
|
588
|
+
```
|
589
|
+
|
590
|
+
## Next Steps
|
591
|
+
|
592
|
+
Now that you understand the API:
|
593
|
+
|
594
|
+
1. **Explore [Getting Started](getting-started.md)** for quick setup
|
595
|
+
2. **Check out [Usage](usage.md)** for practical examples
|
596
|
+
3. **Review [Configuration](configuration.md)** for advanced setup
|
597
|
+
4. **Read [Security](security.md)** for security considerations
|