Usage
This guide covers all usage patterns for OpaqueId, from basic standalone generation to advanced ActiveRecord integration.
- TOC
Standalone ID Generation
OpaqueId can be used independently of ActiveRecord for generating secure, random IDs.
Basic Usage
# Generate a default opaque ID (18 characters, slug-like)
id = OpaqueId.generate
# => "izkpm55j334u8x9y2a"
# Generate multiple IDs
ids = 5.times.map { OpaqueId.generate }
# => ["izkpm55j334u8x9y2a", "k8jh2mn9pl3qr7st1v", ...]
Custom Parameters
# Custom length
id = OpaqueId.generate(size: 10)
# => "izkpm55j334u"
# Custom alphabet
id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
# => "V1StGXR8_Z5jdHi6B-myT"
# Both custom length and alphabet
id = OpaqueId.generate(size: 15, alphabet: OpaqueId::STANDARD_ALPHABET)
# => "V1StGXR8_Z5jdHi6B"
Built-in Alphabets
# Slug-like alphabet (default) - 0-9, a-z
id = OpaqueId.generate(alphabet: OpaqueId::SLUG_LIKE_ALPHABET)
# => "izkpm55j334u8x9y2a"
# Alphanumeric alphabet - A-Z, a-z, 0-9
id = OpaqueId.generate(alphabet: OpaqueId::ALPHANUMERIC_ALPHABET)
# => "V1StGXR8Z5jdHi6BmyT"
# Standard alphabet - A-Z, a-z, 0-9, -, _
id = OpaqueId.generate(alphabet: OpaqueId::STANDARD_ALPHABET)
# => "V1StGXR8_Z5jdHi6B-myT"
Custom Alphabets
# Numeric only
numeric_alphabet = "0123456789"
id = OpaqueId.generate(size: 8, alphabet: numeric_alphabet)
# => "12345678"
# Hexadecimal
hex_alphabet = "0123456789abcdef"
id = OpaqueId.generate(size: 16, alphabet: hex_alphabet)
# => "a1b2c3d4e5f67890"
# URL-safe characters
url_safe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
id = OpaqueId.generate(size: 12, alphabet: url_safe)
# => "izkpm55j334u8x"
ActiveRecord Integration
OpaqueId provides seamless integration with ActiveRecord models through the OpaqueId::Model concern.
Basic Model Setup
class User < ApplicationRecord
include OpaqueId::Model
end
Automatic ID Generation
# Create a new user - opaque_id is automatically generated
user = User.create!(name: "John Doe", email: "john@example.com")
puts user.opaque_id
# => "izkpm55j334u8x9y2a"
# The ID is generated before the record is saved
user = User.new(name: "Jane Smith")
puts user.opaque_id
# => nil (not generated yet)
user.save!
puts user.opaque_id
# => "k8jh2mn9pl3qr7st1va" (generated on save)
Finder Methods
# Find by opaque_id (returns nil if not found)
user = User.find_by_opaque_id("izkpm55j334u8x9y2a")
# Find by opaque_id (raises exception if not found)
user = User.find_by_opaque_id!("izkpm55j334u8x9y2a")
# => ActiveRecord::RecordNotFound if not found
# Use in scopes
class User < ApplicationRecord
include OpaqueId::Model
scope :by_opaque_id, ->(id) { where(opaque_id: id) }
end
users = User.by_opaque_id("izkpm55j334u8x9y2a")
Custom Column Names
class User < ApplicationRecord
include OpaqueId::Model
# Use a different column name
self.opaque_id_column = :public_id
end
# Now the methods use the custom column name
user = User.create!(name: "John Doe")
puts user.public_id
# => "izkpm55j334u8x9y2a"
user = User.find_by_public_id("izkpm55j334u8x9y2a")
Rails Generator
The Rails generator provides a convenient way to set up OpaqueId for your models.
Basic Generator Usage
# Generate setup for a User model
rails generate opaque_id:install User
This creates:
- A migration to add the
opaque_idcolumn - A unique index on the
opaque_idcolumn - Includes the
OpaqueId::Modelconcern in your model
Custom Column Names
# Use a custom column name
rails generate opaque_id:install User --column-name=public_id
This will:
- Create a
public_idcolumn instead ofopaque_id - Add
self.opaque_id_column = :public_idto your model
Multiple Models
# Set up multiple models
rails generate opaque_id:install User
rails generate opaque_id:install Post --column-name=slug
rails generate opaque_id:install Comment
Real-World Examples
E-commerce Application
class Order < ApplicationRecord
include OpaqueId::Model
# Use shorter IDs for orders
self.opaque_id_length = 12
self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
end
# Create an order
order = Order.create!(user_id: 1, total: 99.99)
puts order.opaque_id
# => "izkpm55j334u8x"
# Use in URLs
order_url(order.opaque_id)
# => "/orders/V1StGXR8_Z5j"
API Development
class ApiKey < ApplicationRecord
include OpaqueId::Model
# Use longer IDs for API keys
self.opaque_id_length = 32
self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
end
# Generate API key
api_key = ApiKey.create!(user_id: 1, name: "Mobile App")
puts api_key.opaque_id
# => "V1StGXR8_Z5jdHi6B-myT1234567890"
# Use in API requests
# Authorization: Bearer V1StGXR8_Z5jdHi6B-myT1234567890
Content Management
class Article < ApplicationRecord
include OpaqueId::Model
# Use URL-safe characters for slugs
self.opaque_id_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
self.opaque_id_length = 8
end
# Create an article
article = Article.create!(title: "My Article", content: "Content here")
puts article.opaque_id
# => "V1StGXR8"
# Use in URLs
article_url(article.opaque_id)
# => "/articles/V1StGXR8"
User Management
class User < ApplicationRecord
include OpaqueId::Model
# Require letter start for user IDs
self.opaque_id_require_letter_start = true
end
# Create a user
user = User.create!(name: "John Doe", email: "john@example.com")
puts user.opaque_id
# => "izkpm55j334u8x9y2a" (starts with letter)
# Use in user profiles
user_url(user.opaque_id)
# => "/users/V1StGXR8_Z5jdHi6B-myT"
Advanced Usage Patterns
Batch Operations
# Generate multiple IDs at once
ids = 100.times.map { OpaqueId.generate }
# => ["izkpm55j334u8x9y2a", "k8jh2mn9pl3qr7st1va", ...]
# Use in bulk operations
users_data = ids.map.with_index do |id, index|
{ opaque_id: id, name: "User #{index + 1}" }
end
User.insert_all(users_data)
Conditional ID Generation
class User < ApplicationRecord
include OpaqueId::Model
private
def set_opaque_id
# Only generate ID if not already set
return if opaque_id.present?
# Custom generation logic
self.opaque_id = generate_custom_id
end
def generate_custom_id
# Generate ID with custom logic
base_id = OpaqueId.generate(size: 15)
"usr_#{base_id}"
end
end
Error Handling
class User < ApplicationRecord
include OpaqueId::Model
# Handle generation failures
rescue_from OpaqueId::GenerationError do |exception|
Rails.logger.error "Failed to generate opaque ID: #{exception.message}"
# Fallback to a different generation method
self.opaque_id = generate_fallback_id
end
private
def generate_fallback_id
# Fallback generation method
"fallback_#{SecureRandom.hex(10)}"
end
end
Performance Considerations
Batch Generation
# Efficient batch generation
def generate_batch_ids(count, size: 21, alphabet: OpaqueId::ALPHANUMERIC_ALPHABET)
count.times.map { OpaqueId.generate(size: size, alphabet: alphabet) }
end
# Generate 1000 IDs
ids = generate_batch_ids(1000)
Caching Generated IDs
class User < ApplicationRecord
include OpaqueId::Model
# Cache the generated ID
def opaque_id
@opaque_id ||= super
end
end
Best Practices
1. Choose Appropriate Length
# Short IDs for public URLs
self.opaque_id_length = 8
# Medium IDs for general use
self.opaque_id_length = 21
# Long IDs for sensitive data
self.opaque_id_length = 32
2. Select Suitable Alphabets
# URL-safe for public URLs
self.opaque_id_alphabet = OpaqueId::ALPHANUMERIC_ALPHABET
# Fastest generation
self.opaque_id_alphabet = OpaqueId::STANDARD_ALPHABET
# Custom for specific needs
self.opaque_id_alphabet = "0123456789ABCDEF"
3. Handle Collisions Gracefully
class User < ApplicationRecord
include OpaqueId::Model
# Increase retry attempts for high-volume applications
self.opaque_id_max_retry = 10
end
4. Use Appropriate Finder Methods
# Use find_by_opaque_id for optional lookups
user = User.find_by_opaque_id(params[:id])
# Use find_by_opaque_id! for required lookups
user = User.find_by_opaque_id!(params[:id])
Next Steps
Now that you understand the usage patterns:
- Explore Configuration for advanced setup
- Check out Use Cases for more real-world scenarios
- Review Performance for optimization tips
- Read API Reference for complete documentation
- Learn about Alphabets for custom character sets
- Understand Algorithms for technical details