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.
data/docs/usage.md ADDED
@@ -0,0 +1,417 @@
1
+ ---
2
+ layout: default
3
+ title: Usage
4
+ nav_order: 4
5
+ description: "Complete usage guide with standalone and ActiveRecord examples"
6
+ permalink: /usage/
7
+ ---
8
+
9
+ # Usage
10
+
11
+ This guide covers all usage patterns for OpaqueId, from basic standalone generation to advanced ActiveRecord integration.
12
+
13
+ - TOC
14
+ {:toc}
15
+
16
+ ## Standalone ID Generation
17
+
18
+ OpaqueId can be used independently of ActiveRecord for generating secure, random IDs.
19
+
20
+ ### Basic Usage
21
+
22
+ ```ruby
23
+ # Generate a default opaque ID (21 characters, alphanumeric)
24
+ id = OpaqueId.generate
25
+ # => "V1StGXR8_Z5jdHi6B-myT"
26
+
27
+ # Generate multiple IDs
28
+ ids = 5.times.map { OpaqueId.generate }
29
+ # => ["V1StGXR8_Z5jdHi6B-myT", "K8jH2mN9_pL3qR7sT1v", ...]
30
+ ```
31
+
32
+ ### Custom Parameters
33
+
34
+ ```ruby
35
+ # Custom length
36
+ id = OpaqueId.generate(size: 10)
37
+ # => "V1StGXR8_Z5"
38
+
39
+ # Custom alphabet
40
+ id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
41
+ # => "V1StGXR8_Z5jdHi6B-myT"
42
+
43
+ # Both custom length and alphabet
44
+ id = OpaqueId.generate(size: 15, alphabet: OpaqueId::STANDARD_ALPHABET)
45
+ # => "V1StGXR8_Z5jdHi"
46
+ ```
47
+
48
+ ### Built-in Alphabets
49
+
50
+ ```ruby
51
+ # Alphanumeric alphabet (default) - A-Z, a-z, 0-9
52
+ id = OpaqueId.generate(alphabet: OpaqueId::ALPHANUMERIC_ALPHABET)
53
+ # => "V1StGXR8_Z5jdHi6B-myT"
54
+
55
+ # Standard alphabet - A-Z, a-z, 0-9, -, _
56
+ id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
57
+ # => "V1StGXR8_Z5jdHi6B-myT"
58
+ ```
59
+
60
+ ### Custom Alphabets
61
+
62
+ ```ruby
63
+ # Numeric only
64
+ numeric_alphabet = "0123456789"
65
+ id = OpaqueId.generate(size: 8, alphabet: numeric_alphabet)
66
+ # => "12345678"
67
+
68
+ # Hexadecimal
69
+ hex_alphabet = "0123456789abcdef"
70
+ id = OpaqueId.generate(size: 16, alphabet: hex_alphabet)
71
+ # => "a1b2c3d4e5f67890"
72
+
73
+ # URL-safe characters
74
+ url_safe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
75
+ id = OpaqueId.generate(size: 12, alphabet: url_safe)
76
+ # => "V1StGXR8_Z5j"
77
+ ```
78
+
79
+ ## ActiveRecord Integration
80
+
81
+ OpaqueId provides seamless integration with ActiveRecord models through the `OpaqueId::Model` concern.
82
+
83
+ ### Basic Model Setup
84
+
85
+ ```ruby
86
+ class User < ApplicationRecord
87
+ include OpaqueId::Model
88
+ end
89
+ ```
90
+
91
+ ### Automatic ID Generation
92
+
93
+ ```ruby
94
+ # Create a new user - opaque_id is automatically generated
95
+ user = User.create!(name: "John Doe", email: "john@example.com")
96
+ puts user.opaque_id
97
+ # => "V1StGXR8_Z5jdHi6B-myT"
98
+
99
+ # The ID is generated before the record is saved
100
+ user = User.new(name: "Jane Smith")
101
+ puts user.opaque_id
102
+ # => nil (not generated yet)
103
+
104
+ user.save!
105
+ puts user.opaque_id
106
+ # => "K8jH2mN9_pL3qR7sT1v" (generated on save)
107
+ ```
108
+
109
+ ### Finder Methods
110
+
111
+ ```ruby
112
+ # Find by opaque_id (returns nil if not found)
113
+ user = User.find_by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
114
+
115
+ # Find by opaque_id (raises exception if not found)
116
+ user = User.find_by_opaque_id!("V1StGXR8_Z5jdHi6B-myT")
117
+ # => ActiveRecord::RecordNotFound if not found
118
+
119
+ # Use in scopes
120
+ class User < ApplicationRecord
121
+ include OpaqueId::Model
122
+
123
+ scope :by_opaque_id, ->(id) { where(opaque_id: id) }
124
+ end
125
+
126
+ users = User.by_opaque_id("V1StGXR8_Z5jdHi6B-myT")
127
+ ```
128
+
129
+ ### Custom Column Names
130
+
131
+ ```ruby
132
+ class User < ApplicationRecord
133
+ include OpaqueId::Model
134
+
135
+ # Use a different column name
136
+ self.opaque_id_column = :public_id
137
+ end
138
+
139
+ # Now the methods use the custom column name
140
+ user = User.create!(name: "John Doe")
141
+ puts user.public_id
142
+ # => "V1StGXR8_Z5jdHi6B-myT"
143
+
144
+ user = User.find_by_public_id("V1StGXR8_Z5jdHi6B-myT")
145
+ ```
146
+
147
+ ## Rails Generator
148
+
149
+ The Rails generator provides a convenient way to set up OpaqueId for your models.
150
+
151
+ ### Basic Generator Usage
152
+
153
+ ```bash
154
+ # Generate setup for a User model
155
+ rails generate opaque_id:install User
156
+ ```
157
+
158
+ This creates:
159
+
160
+ - A migration to add the `opaque_id` column
161
+ - A unique index on the `opaque_id` column
162
+ - Includes the `OpaqueId::Model` concern in your model
163
+
164
+ ### Custom Column Names
165
+
166
+ ```bash
167
+ # Use a custom column name
168
+ rails generate opaque_id:install User --column-name=public_id
169
+ ```
170
+
171
+ This will:
172
+
173
+ - Create a `public_id` column instead of `opaque_id`
174
+ - Add `self.opaque_id_column = :public_id` to your model
175
+
176
+ ### Multiple Models
177
+
178
+ ```bash
179
+ # Set up multiple models
180
+ rails generate opaque_id:install User
181
+ rails generate opaque_id:install Post --column-name=slug
182
+ rails generate opaque_id:install Comment
183
+ ```
184
+
185
+ ## Real-World Examples
186
+
187
+ ### E-commerce Application
188
+
189
+ ```ruby
190
+ class Order < ApplicationRecord
191
+ include OpaqueId::Model
192
+
193
+ # Use shorter IDs for orders
194
+ self.opaque_id_length = 12
195
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
196
+ end
197
+
198
+ # Create an order
199
+ order = Order.create!(user_id: 1, total: 99.99)
200
+ puts order.opaque_id
201
+ # => "V1StGXR8_Z5j"
202
+
203
+ # Use in URLs
204
+ order_url(order.opaque_id)
205
+ # => "/orders/V1StGXR8_Z5j"
206
+ ```
207
+
208
+ ### API Development
209
+
210
+ ```ruby
211
+ class ApiKey < ApplicationRecord
212
+ include OpaqueId::Model
213
+
214
+ # Use longer IDs for API keys
215
+ self.opaque_id_length = 32
216
+ self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
217
+ end
218
+
219
+ # Generate API key
220
+ api_key = ApiKey.create!(user_id: 1, name: "Mobile App")
221
+ puts api_key.opaque_id
222
+ # => "V1StGXR8_Z5jdHi6B-myT1234567890"
223
+
224
+ # Use in API requests
225
+ # Authorization: Bearer V1StGXR8_Z5jdHi6B-myT1234567890
226
+ ```
227
+
228
+ ### Content Management
229
+
230
+ ```ruby
231
+ class Article < ApplicationRecord
232
+ include OpaqueId::Model
233
+
234
+ # Use URL-safe characters for slugs
235
+ self.opaque_id_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
236
+ self.opaque_id_length = 8
237
+ end
238
+
239
+ # Create an article
240
+ article = Article.create!(title: "My Article", content: "Content here")
241
+ puts article.opaque_id
242
+ # => "V1StGXR8"
243
+
244
+ # Use in URLs
245
+ article_url(article.opaque_id)
246
+ # => "/articles/V1StGXR8"
247
+ ```
248
+
249
+ ### User Management
250
+
251
+ ```ruby
252
+ class User < ApplicationRecord
253
+ include OpaqueId::Model
254
+
255
+ # Require letter start for user IDs
256
+ self.opaque_id_require_letter_start = true
257
+ end
258
+
259
+ # Create a user
260
+ user = User.create!(name: "John Doe", email: "john@example.com")
261
+ puts user.opaque_id
262
+ # => "V1StGXR8_Z5jdHi6B-myT" (starts with letter)
263
+
264
+ # Use in user profiles
265
+ user_url(user.opaque_id)
266
+ # => "/users/V1StGXR8_Z5jdHi6B-myT"
267
+ ```
268
+
269
+ ## Advanced Usage Patterns
270
+
271
+ ### Batch Operations
272
+
273
+ ```ruby
274
+ # Generate multiple IDs at once
275
+ ids = 100.times.map { OpaqueId.generate }
276
+ # => ["V1StGXR8_Z5jdHi6B-myT", "K8jH2mN9_pL3qR7sT1v", ...]
277
+
278
+ # Use in bulk operations
279
+ users_data = ids.map.with_index do |id, index|
280
+ { opaque_id: id, name: "User #{index + 1}" }
281
+ end
282
+
283
+ User.insert_all(users_data)
284
+ ```
285
+
286
+ ### Conditional ID Generation
287
+
288
+ ```ruby
289
+ class User < ApplicationRecord
290
+ include OpaqueId::Model
291
+
292
+ private
293
+
294
+ def set_opaque_id
295
+ # Only generate ID if not already set
296
+ return if opaque_id.present?
297
+
298
+ # Custom generation logic
299
+ self.opaque_id = generate_custom_id
300
+ end
301
+
302
+ def generate_custom_id
303
+ # Generate ID with custom logic
304
+ base_id = OpaqueId.generate(size: 15)
305
+ "usr_#{base_id}"
306
+ end
307
+ end
308
+ ```
309
+
310
+ ### Error Handling
311
+
312
+ ```ruby
313
+ class User < ApplicationRecord
314
+ include OpaqueId::Model
315
+
316
+ # Handle generation failures
317
+ rescue_from OpaqueId::GenerationError do |exception|
318
+ Rails.logger.error "Failed to generate opaque ID: #{exception.message}"
319
+ # Fallback to a different generation method
320
+ self.opaque_id = generate_fallback_id
321
+ end
322
+
323
+ private
324
+
325
+ def generate_fallback_id
326
+ # Fallback generation method
327
+ "fallback_#{SecureRandom.hex(10)}"
328
+ end
329
+ end
330
+ ```
331
+
332
+ ## Performance Considerations
333
+
334
+ ### Batch Generation
335
+
336
+ ```ruby
337
+ # Efficient batch generation
338
+ def generate_batch_ids(count, size: 21, alphabet: OpaqueId::ALPHANUMERIC_ALPHABET)
339
+ count.times.map { OpaqueId.generate(size: size, alphabet: alphabet) }
340
+ end
341
+
342
+ # Generate 1000 IDs
343
+ ids = generate_batch_ids(1000)
344
+ ```
345
+
346
+ ### Caching Generated IDs
347
+
348
+ ```ruby
349
+ class User < ApplicationRecord
350
+ include OpaqueId::Model
351
+
352
+ # Cache the generated ID
353
+ def opaque_id
354
+ @opaque_id ||= super
355
+ end
356
+ end
357
+ ```
358
+
359
+ ## Best Practices
360
+
361
+ ### 1. Choose Appropriate Length
362
+
363
+ ```ruby
364
+ # Short IDs for public URLs
365
+ self.opaque_id_length = 8
366
+
367
+ # Medium IDs for general use
368
+ self.opaque_id_length = 21
369
+
370
+ # Long IDs for sensitive data
371
+ self.opaque_id_length = 32
372
+ ```
373
+
374
+ ### 2. Select Suitable Alphabets
375
+
376
+ ```ruby
377
+ # URL-safe for public URLs
378
+ self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
379
+
380
+ # Fastest generation
381
+ self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
382
+
383
+ # Custom for specific needs
384
+ self.opaque_id_alphabet = "0123456789ABCDEF"
385
+ ```
386
+
387
+ ### 3. Handle Collisions Gracefully
388
+
389
+ ```ruby
390
+ class User < ApplicationRecord
391
+ include OpaqueId::Model
392
+
393
+ # Increase retry attempts for high-volume applications
394
+ self.opaque_id_max_retry = 10
395
+ end
396
+ ```
397
+
398
+ ### 4. Use Appropriate Finder Methods
399
+
400
+ ```ruby
401
+ # Use find_by_opaque_id for optional lookups
402
+ user = User.find_by_opaque_id(params[:id])
403
+
404
+ # Use find_by_opaque_id! for required lookups
405
+ user = User.find_by_opaque_id!(params[:id])
406
+ ```
407
+
408
+ ## Next Steps
409
+
410
+ Now that you understand the usage patterns:
411
+
412
+ 1. **Explore [Configuration](configuration.md)** for advanced setup
413
+ 2. **Check out [Use Cases](use-cases.md)** for more real-world scenarios
414
+ 3. **Review [Performance](performance.md)** for optimization tips
415
+ 4. **Read [API Reference](api-reference.md)** for complete documentation
416
+ 5. **Learn about [Alphabets](alphabets.md)** for custom character sets
417
+ 6. **Understand [Algorithms](algorithms.md)** for technical details