Skip to main content

Ruby SDK

The Ruby SDK provides a thread-safe client for evaluating feature flags in Ruby applications.

Installation

Add to your Gemfile:

gem "featuresignals"

Or install directly:

gem install featuresignals

Requirements: Ruby 3.1+

Quick Start

require "featuresignals"

options = FeatureSignals::ClientOptions.new(env_key: "production")
client = FeatureSignals::Client.new("fs_srv_your_api_key", options)
client.wait_for_ready

user = FeatureSignals::EvalContext.new(key: "user-123", attributes: { "plan" => "pro" })

enabled = client.bool_variation("new-feature", user, false)
puts "Feature enabled: #{enabled}"

Configuration

options = FeatureSignals::ClientOptions.new(
env_key: "production",
base_url: "http://localhost:8080",
polling_interval: 15,
streaming: true,
sse_retry: 3,
timeout: 10,
)
OptionTypeDefaultDescription
env_keyString(required)Environment slug
base_urlStringhttps://api.featuresignals.comAPI server URL
polling_intervalNumeric30Polling frequency in seconds
streamingBooleanfalseEnable SSE streaming
sse_retryNumeric5SSE reconnect delay in seconds
timeoutNumeric10HTTP timeout in seconds

Variation Methods

enabled = client.bool_variation("flag-key", ctx, false)
value = client.string_variation("banner-text", ctx, "default")
limit = client.number_variation("rate-limit", ctx, 100.0)
config = client.json_variation("config", ctx, { "v" => 1 })

Evaluation Context

user = FeatureSignals::EvalContext.new(key: "user-42")

# with_attribute returns a new copy (immutable)
rich_user = user
.with_attribute("plan", "enterprise")
.with_attribute("country", "US")

Lifecycle

# Wait for initial flags
client.wait_for_ready(timeout: 10)

# Check readiness
if client.ready?
# ...
end

# Get all flags
flags = client.all_flags

# Shutdown
client.close

Callbacks

client = FeatureSignals::Client.new("key", options,
on_ready: -> { puts "Flags loaded" },
on_error: ->(err) { warn "Error: #{err}" },
on_update: ->(flags) { puts "Updated: #{flags.size} flags" },
)

Rails Integration

Create an initializer at config/initializers/feature_signals.rb:

Rails.application.config.to_prepare do
options = FeatureSignals::ClientOptions.new(
env_key: Rails.env.production? ? "production" : "development",
base_url: ENV.fetch("FEATURESIGNALS_URL", "http://localhost:8080"),
streaming: true,
)
FEATURE_FLAGS = FeatureSignals::Client.new(
ENV.fetch("FEATURESIGNALS_API_KEY"), options
)
end

at_exit { FEATURE_FLAGS&.close }

Use in controllers:

class CheckoutController < ApplicationController
def show
user = FeatureSignals::EvalContext.new(
key: current_user.id.to_s,
attributes: { "plan" => current_user.plan }
)
if FEATURE_FLAGS.bool_variation("new-checkout", user, false)
render :new_checkout
else
render :checkout
end
end
end

Sinatra

require "sinatra"
require "featuresignals"

flags = FeatureSignals::Client.new("fs_srv_xxx",
FeatureSignals::ClientOptions.new(env_key: "production"))

get "/feature" do
ctx = FeatureSignals::EvalContext.new(key: params[:user_id] || "anonymous")
{ enabled: flags.bool_variation("my-flag", ctx, false) }.to_json
end

OpenFeature

provider = FeatureSignals::OpenFeature::Provider.new("fs_srv_xxx", options)
result = provider.resolve_boolean_evaluation("new-feature", false)
puts "#{result.value} (#{result.reason})"
provider.shutdown

Thread Safety

  • All variation methods are thread-safe (backed by Mutex)
  • EvalContext#with_attribute returns a new object
  • close is idempotent