Skip to content

ToggleCraft/ruby-sdk

Repository files navigation

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 togglecraft

Quick 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
end

Rails

# 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
end

Then 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
end

Basic Usage

Boolean Flags

Simple on/off feature toggles:

if client.enabled?('dark-mode', user: { id: '123' })
  enable_dark_mode
end

Multivariate 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
end

Percentage Rollouts

Gradual feature rollouts:

if client.in_percentage?('new-algorithm', user: { id: '123' })
  use_new_algorithm
else
  use_legacy_algorithm
end

Configuration

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
end

Full 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}"
end

Error 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
end

Best Practices

  1. Initialize Once - Create a single client instance and reuse it
  2. Always Provide Context - Include at least user.id for consistent evaluation
  3. Use Default Values - Handle missing flags gracefully
  4. Clean Up on Shutdown - Call client.destroy when closing
# On application shutdown
at_exit do
  client.destroy
end

API 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

Full API Documentation →

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

Advanced Features Guide →

Troubleshooting

Client not connecting?

  • Verify your SDK key is correct
  • Check that you called connect before 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

More Troubleshooting →

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

License

MIT

Contributing

Contributions are welcome! Please open an issue or submit a pull request on GitHub.

Support

About

No description, website, or topics provided.

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages