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