ToggleCraft Ruby SDK
A lightweight, real-time feature flag SDK for Ruby applications. Thread-safe, Rails-friendly, and built for production.
Why ToggleCraft?
- ๐ Real-time Updates - Instant flag changes via Server-Sent Events
- ๐งต Thread-Safe - Built for Puma, Sidekiq, and multi-threaded environments
- ๐พ Smart Caching - Works offline with memory or Redis support
- ๐ Production Ready - 214 passing tests with comprehensive coverage
- ๐ Universal - Works with Rails, Sinatra, Hanami, and standalone Ruby
- โป๏ธ Auto-reconnection - Resilient connection handling
Installation
Add to your Gemfile:
gem 'togglecraft'Or install directly:
gem install togglecraftQuick Start
Ruby
require 'togglecraft'
# Initialize client
client = ToggleCraft::Client.new(sdk_key: 'your-sdk-key')
# Connect and wait for flags
client.connect
client.wait_for_ready
# Use your flags
if client.enabled?('new-feature', user: { id: current_user.id })
# Feature is enabled
endRails
# config/initializers/togglecraft.rb
Rails.application.config.togglecraft = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY'],
cache_adapter: :memory,
logger: Rails.logger,
debug: Rails.env.development?
)
Rails.application.config.togglecraft.connect
at_exit do
Rails.application.config.togglecraft.destroy
endThen use in your controllers:
class DashboardController < ApplicationController
def index
if togglecraft.enabled?('premium-dashboard', user: { id: current_user.id })
render :premium
else
render :standard
end
end
private
def togglecraft
Rails.application.config.togglecraft
end
endBasic Usage
Boolean Flags
Simple on/off feature toggles:
if client.enabled?('dark-mode', user: { id: '123' })
enable_dark_mode
endMultivariate Flags
A/B/n testing with multiple variants:
variant = client.variant('checkout-flow', user: { id: '123' })
case variant
when 'one-page'
render_one_page_checkout
when 'multi-step'
render_multi_step_checkout
else
render_default_checkout
endPercentage Rollouts
Gradual feature rollouts:
if client.in_percentage?('new-algorithm', user: { id: '123' })
use_new_algorithm
else
use_legacy_algorithm
endConfiguration
client = ToggleCraft::Client.new(
# Required
sdk_key: 'your-sdk-key', # Get from ToggleCraft dashboard
# Optional - Common settings
enable_cache: true, # Enable caching (default: true)
cache_adapter: :memory, # :memory or :redis (default: :memory)
cache_ttl: 300, # Cache TTL in seconds (default: 5 minutes)
debug: false # Enable debug logging (default: false)
)Need more control? See Advanced Configuration โ
Evaluation Context
The context object provides data for targeting rules:
context = {
user: {
id: 'user-123', # Required for consistent evaluation
email: 'user@example.com',
plan: 'premium',
# Add any custom attributes you need
role: 'admin',
company_id: 'acme-corp'
},
request: {
ip: '192.168.1.1',
country: 'US'
},
device: {
type: 'mobile',
os: 'iOS'
}
}
client.enabled?('premium-feature', context)You can add any custom properties - the SDK evaluates all attributes using dot notation (e.g., user.role, request.country).
Framework Integration
Rails
# config/initializers/togglecraft.rb
Rails.application.config.togglecraft = ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY'],
cache_adapter: :memory,
logger: Rails.logger
)Full Rails Integration Guide โ
Sidekiq
class FeatureWorker
include Sidekiq::Worker
def togglecraft
@togglecraft ||= ToggleCraft::Client.new(
sdk_key: ENV['TOGGLECRAFT_SDK_KEY'],
share_connection: true # Share connection with other workers
)
end
def perform(user_id)
togglecraft.connect unless togglecraft.connected?
if togglecraft.enabled?('batch-processing', user: { id: user_id })
# Use new batch processing
end
end
endFull Sidekiq Integration Guide โ
Event Handling
Listen for real-time updates:
# Flags are ready
client.on(:ready) do
puts 'Client ready!'
end
# Flags updated in real-time
client.on(:flags_updated) do |flags|
puts "Flags updated: #{flags.keys.join(', ')}"
end
# Connection lost
client.on(:disconnected) do
puts 'Disconnected - using cached flags'
end
# Error occurred
client.on(:error) do |error|
logger.error "ToggleCraft error: #{error}"
endError Handling
Always provide default values and handle errors gracefully:
# Safe evaluation with defaults
is_enabled = client.enabled?('feature', context, default: false)
# Returns false if flag doesn't exist or on error
# Handle connection errors
begin
client.connect
rescue StandardError => e
logger.error "Failed to connect: #{e}"
# App still works with cached values or defaults
endBest Practices
- Initialize Once - Create a single client instance and reuse it
-
Always Provide Context - Include at least
user.idfor consistent evaluation - Use Default Values - Handle missing flags gracefully
-
Clean Up on Shutdown - Call
client.destroywhen closing
# On application shutdown
at_exit do
client.destroy
endAPI Reference
Core Methods:
-
enabled?(flag_key, context = {}, default: false)- Check boolean flags -
variant(flag_key, context = {}, default: nil)- Get multivariate variant -
in_percentage?(flag_key, context = {}, default: false)- Check percentage rollout
Connection:
-
connect- Connect to SSE server -
disconnect- Disconnect from server -
ready?- Check if client has flags loaded -
wait_for_ready(timeout: 5)- Wait for client to be ready
Advanced Features
Power users can customize:
- Connection pooling and reconnection strategies
- Scheduled rollout stages with automatic transitions
- Redis cache adapter
- Hybrid reconnection with exponential backoff
Troubleshooting
Client not connecting?
- Verify your SDK key is correct
- Check that you called
connectbefore using the client - Ensure your firewall allows connections to
sse.togglecraft.io
Flags not updating?
- Verify the SSE connection is established (
client.connected?) - Check the logs for error messages
- Enable debug mode:
debug: true
Requirements
- Ruby 3.0+
-
Dependencies:
-
concurrent-ruby(~> 1.2) - Thread-safe data structures -
http(~> 5.0) - HTTP client for API requests -
semantic(~> 1.6) - Semantic version comparison
-
Thread Safety
This SDK is fully thread-safe and production-ready for:
- Puma - Multi-threaded Rails server
- Sidekiq - Background job processing
- Any multi-threaded Ruby environment
All critical sections use Concurrent::Map, Mutex, and Concurrent::AtomicBoolean for thread safety.
Documentation
- API Reference - Complete API documentation
- Advanced Features - Connection pooling, rollout stages, custom configuration
- Framework Integration - Rails, Sidekiq, and other framework guides
- Troubleshooting - Common issues and solutions
- Security - Security best practices and policies
License
MIT
Contributing
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
Support
- Documentation: GitHub Repository
- Issues: GitHub Issues
- Security: See SECURITY.md for reporting vulnerabilities