### Install Rails and Split Gem
Source: https://github.com/splitrb/split/wiki/Tutorial
Installs Ruby on Rails, creates a new Rails application, and adds the Split gem to the Gemfile. Includes commands for installing Redis on macOS and Debian/Ubuntu.
```bash
gem install rails
rails new split-example
cd split-example
# For macOS
brew install redis
# For Ubuntu/Debian
sudo apt-get install redis-server
```
--------------------------------
### Install Redis on macOS
Source: https://github.com/splitrb/split/blob/main/README.md
Installs and starts a Redis server on macOS using Homebrew. This is a prerequisite for using the Split gem.
```bash
brew install redis
redis-server /usr/local/etc/redis.conf
```
--------------------------------
### Configure Dual Persistence Adapter
Source: https://github.com/splitrb/split/blob/main/README.md
Implement a dual persistence strategy using different adapters for logged-in and logged-out users. This example uses Redis for logged-in users and cookies for logged-out users, with custom configuration for each.
```ruby
cookie_adapter = Split::Persistence::CookieAdapter
redis_adapter = Split::Persistence::RedisAdapter.with_config(
lookup_by: -> (context) { context.send(:current_user).try(:id) },
expire_seconds: 2592000)
Split.configure do |config|
config.persistence = Split::Persistence::DualAdapter.with_config(
logged_in: -> (context) { !context.send(:current_user).try(:id).nil? },
logged_in_adapter: redis_adapter,
logged_out_adapter: cookie_adapter)
config.persistence_cookie_length = 2592000 # 30 days
end
```
--------------------------------
### Start A/B Test Experiment with Redis Persistence - Ruby
Source: https://github.com/splitrb/split/wiki/Use-Split-outside-a-web-request
This snippet demonstrates how to initiate an A/B test experiment using a Redis adapter for persistence. It sets up a user with a custom Redis key and selects an alternative for the trial. The `choose!` method is essential for assigning an experiment variant to the user.
```ruby
# Begin the test for an object
experiment_name = 'my_experience'
key = "thing-#{thing.id}"
ab_user = Split::User.new(nil, Split::Persistence::RedisAdapter.new(nil, key))
experiment = Split::ExperimentCatalog.find_or_create(experiment_name, 'variant_A', 'variant_B')
trial = Split::Trial.new(user: ab_user, experiment: experiment)
trial.choose!
puts trial.alternative.name
```
--------------------------------
### Basic Experiment Usage in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Illustrates the simplified method calls for starting and finishing experiments after they have been configured. These functions abstract the underlying experiment logic.
```ruby
ab_test(:my_first_experiment)
```
```ruby
ab_finished(:my_first_experiment)
```
--------------------------------
### Add Split and SystemTimer to Gemfile
Source: https://github.com/splitrb/split/wiki/Tutorial
Adds the Split gem for A/B testing and the SystemTimer gem (for Ruby 1.8.x) to the application's Gemfile, ensuring Redis client stability. After adding, run `bundle install` to install the gems.
```ruby
gem 'split'
# For Ruby 1.8.x
gem 'SystemTimer'
```
--------------------------------
### Split Gem Configuration and Redis Setup (Ruby)
Source: https://github.com/splitrb/split/wiki/Use-Split-with-Heroku-RedisToGo
This configuration file sets up the Split gem with various options including database failover, allowing multiple experiments, and enabling the gem. It also includes logic to configure Redis connections using RedisToGo on Heroku, including namespace management. The dashboard authentication is also configured.
```ruby
# config/initializers/split.rb
Split.configure do |config|
# config.robot_regex = /my_custom_robot_regex/ # Should set it
# config.ignore_ip_addresses << '81.19.48.130' # You should set it using SettingsLogic or something
config.db_failover = true # handle redis errors gracefully
config.db_failover_on_db_error = proc{|error| Rails.logger.error(error.message) }
config.allow_multiple_experiments = true # It's fine for me, but might not for you
config.enabled = true
end
Split::Dashboard.use Rack::Auth::Basic do |username, password|
username == 'fire_in' && password == 'the_hole' # This one is fake :P
end
if ENV["REDISTOGO_URL"]
uri = URI.parse(ENV["REDISTOGO_URL"])
namespace = ["split", "myapp", Rails.env].join(":")
redis = Redis.new(host: uri.host,
port: uri.port,
password: uri.password,
thread_safe: true
)
redis_namespace = Redis::Namespace.new(namespace, redis: redis)
Split.redis = redis_namespace
end
```
--------------------------------
### Start Combined Experiments
Source: https://github.com/splitrb/split/blob/main/README.md
Provides the Ruby method to initiate a combined experiment. Starting the parent experiment automatically starts all associated combined experiments.
```ruby
ab_combined_test(:button_color_experiment)
```
--------------------------------
### Start an A/B Test in Ruby
Source: https://github.com/splitrb/split/wiki/Hints-and-tips
Initiates an A/B test by defining the test name and its alternatives. The first alternative serves as the control, which is used as a fallback when Redis connections fail and for statistical comparison on the dashboard.
```ruby
ab_test("ab_test_name", "old version", "new version 1", "new version 2", etc...)
```
--------------------------------
### Define Experiments in Split Gem Configuration
Source: https://context7.com/splitrb/split/llms.txt
Pre-configures experiments with alternatives, weights, goals, and metadata directly within the initializer. Experiments can be defined using a hash or loaded from a YAML file. This allows for declarative experiment setup.
```ruby
# config/initializers/split.rb
Split.configure do |config|
config.experiments = {
button_color: {
alternatives: ["red", "blue", "green"],
resettable: false
},
pricing_display: {
alternatives: [
{name: "monthly_first", percent: 50},
{name: "annual_first", percent: 50}
],
goals: ["signup", "purchase"],
metadata: {
"monthly_first" => {
"headline" => "Flexible Monthly Plans",
"emphasis" => "monthly"
},
"annual_first" => {
"headline" => "Best Value - Annual Plans",
"emphasis" => "annual"
}
}
},
checkout_optimization: {
algorithm: "Split::Algorithms::Whiplash",
alternatives: ["single_page", "multi_step", "accordion"],
metric: :checkout_conversion
}
}
end
# Alternative: Load from YAML
# config.experiments = YAML.load_file("config/experiments.yml")
# config/experiments.yml
# button_test:
# alternatives:
# - red
# - blue
# metadata:
# red:
# hex: "#FF0000"
# blue:
# hex: "#0000FF"
# Usage in code (simplified)
ab_test(:button_color) # No need to specify alternatives
ab_finished(:button_color) # Just reference by name
```
--------------------------------
### Finish Individual Combined Experiments
Source: https://github.com/splitrb/split/blob/main/README.md
Shows how to finish individual experiments that are part of a combined experiment setup. Each combined experiment can be finished independently.
```ruby
ab_finished(:button_color_on_login)
ab_finished(:button_color_on_signup)
```
--------------------------------
### Run A/B Test Experiment with ab_test
Source: https://context7.com/splitrb/split/llms.txt
The `ab_test` method starts or continues an A/B test experiment, assigning users to alternatives and ensuring consistent assignment across requests. It supports basic tests, block syntax, weighted alternatives, metadata access, and multiple alternatives.
```ruby
class SignupController < ApplicationController
def new
@button_color = ab_test(:signup_button_color, "red", "blue")
# Returns "red" or "blue" consistently for this user
end
end
# A/B test with block syntax in view
<%= ab_test(:pricing_layout, "simple", "detailed") do |layout|
<%= render partial: "pricing_#{layout}" %>
<% end %>
# Test with weighted alternatives (90% control, 10% experimental)
def homepage
@design = ab_test(:homepage_redesign, {"old_design" => 9}, {"new_design" => 1})
end
# Test with metadata access
<% ab_test(:welcome_message) do |alternative, metadata|
<%= metadata["headline"] %>
<%= metadata["subtext"] %>
<% end %>
# Test with multiple alternatives
def onboarding
@free_credits = ab_test(:new_user_credits, "100", "200", "300", "500")
# Assigns one of four values to test optimal starting credits
end
```
--------------------------------
### Configure Redis from YAML File
Source: https://github.com/splitrb/split/wiki/Tutorial
Loads Redis configuration from a `config/split.yml` file based on the current Rails environment. The initializer reads the environment-specific host and port and constructs the Redis connection URL.
```yaml
development: localhost:6379
test: localhost:6379
staging: redis1.example.com:6379
fi: localhost:6379
production: redis1.example.com:6379
```
```ruby
rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..'
rails_env = ENV['RAILS_ENV'] || 'development'
split_config = YAML.load_file(rails_root + '/config/split.yml')
Split.redis = 'redis://' + split_config[rails_env]
```
--------------------------------
### Run an Experiment Outside a Web Session
Source: https://github.com/splitrb/split/blob/main/README.md
Provides an example of how to manually run A/B tests using Split's core objects outside of a web session context. This includes creating experiments, users, trials, and completing goals.
```ruby
# create a new experiment
experiment = Split::ExperimentCatalog.find_or_create('color', 'red', 'blue')
# find the user
user = Split::User.find(user_id, :redis)
# create a new trial
trial = Split::Trial.new(user: user, experiment: experiment)
# run trial
trial.choose!
# get the result, returns either red or blue
trial.alternative.name
# if the goal has been achieved, increment the successful completions for this alternative.
if goal_achieved?
trial.complete!
end
```
--------------------------------
### Get Active Experiments for a User - Ruby
Source: https://github.com/splitrb/split/wiki/Use-Split-outside-a-web-request
This Ruby example illustrates how to retrieve all active A/B experiments assigned to a specific user. It utilizes a Redis adapter with a predefined user ID to fetch the user object and then calls the `active_experiments` method on it. The result is a hash mapping experiment names to their assigned variants.
```ruby
# Getting active experiments from a given user
ab_user = Split::User.new(nil, Split::Persistence::RedisAdapter.new(nil, 'user_id'))
ab_user.active_experiments
# => {"link_text_2"=>"Click Here"}
```
--------------------------------
### Accessing Experiment Alternative and Metadata
Source: https://github.com/splitrb/split/blob/main/README.md
Provides examples of how to access the selected alternative's name and its associated metadata in Ruby code. This is useful for dynamically changing application behavior based on experiment results.
```ruby
trial.alternative.name # => "a"
trial.metadata['text'] # => "Have a fantastic day"
```
--------------------------------
### Define Trial Event Hook Methods in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Provides example implementations for trial event hook methods. These methods are expected to accept a `Trial` object and can perform actions like logging experiment participation details, including the experiment name, chosen alternative, and user ID.
```ruby
def log_trial(trial)
logger.info "experiment=%s alternative=%s user=%s" %
[ trial.experiment.name, trial.alternative, current_user.id ]
end
def log_trial_choose(trial)
logger.info "[new user] experiment=%s alternative=%s user=%s" %
[ trial.experiment.name, trial.alternative, current_user.id ]
end
def log_trial_complete(trial)
logger.info "experiment=%s alternative=%s user=%s complete=true" %
[ trial.experiment.name, trial.alternative, current_user.id ]
end
```
--------------------------------
### Example RSpec Test Using `use_ab_test` Helper
Source: https://github.com/splitrb/split/blob/main/README.md
Demonstrates how to use the `use_ab_test` helper method within an RSpec test to force a specific experiment alternative. This ensures that the test environment consistently uses the intended variant for testing.
```ruby
it "registers using experimental signup" do
use_ab_test experiment_name: "alternative_name"
post "/signups"
...
end
```
--------------------------------
### Test Checkout Flow Variations with A/B Testing (Ruby)
Source: https://context7.com/splitrb/split/llms.txt
These RSpec tests for the CheckoutController demonstrate how to use the `use_ab_test` helper to simulate different checkout flow configurations. Each test sets up a specific A/B test scenario and then makes a GET request to the `new` action, asserting that the correct template is rendered based on the mocked experiment outcome.
```ruby
RSpec.describe CheckoutController, type: :controller do
describe "GET #new" do
it "renders single page checkout" do
use_ab_test(checkout_flow: "single_page")
get :new
expect(response).to render_template("checkout/single_page")
expect(assigns(:checkout_type)).to eq("single_page")
end
it "renders multi-step checkout" do
use_ab_test(checkout_flow: "multi_step")
get :new
expect(response).to render_template("checkout/multi_step")
end
end
end
```
--------------------------------
### Track Experiment Conversion in View
Source: https://github.com/splitrb/split/blob/main/README.md
Provides an example of tracking experiment conversion directly within an ERB view using the `ab_finished` method. This is useful for tracking conversions that occur on a specific page or action within the view.
```erb
Thanks for signing up, dude! <% ab_finished(:signup_page_redesign) %>
```
--------------------------------
### Test UI Element Variations with A/B Testing (Ruby)
Source: https://context7.com/splitrb/split/llms.txt
This RSpec test verifies the rendering of UI elements based on A/B test configurations. It uses the `use_ab_test` helper to set specific experiment variations for 'button_color' and 'pricing_layout', then makes a GET request to the 'pricing' action and asserts that the response body includes the expected HTML class names corresponding to the chosen alternatives.
```ruby
RSpec.describe CheckoutController, type: :controller do
# ... other tests ...
it "shows blue button and simple pricing" do
use_ab_test(
button_color: "blue",
pricing_layout: "simple"
)
get :pricing
expect(response.body).to include("blue-button")
expect(response.body).to include("simple-pricing")
end
end
```
--------------------------------
### Configure Redis Connection String
Source: https://github.com/splitrb/split/wiki/Tutorial
Sets the Redis connection string for Split to use. This can be a simple URL or a pre-existing Redis object. Examples show setting a URL and using a global Redis object.
```ruby
Split.redis = 'redis://localhost:6379'
Split.redis = $redis
```
--------------------------------
### Configure Robot Detection Regex
Source: https://github.com/splitrb/split/wiki/Tutorial
Overrides the default regular expression used by Split to detect and ignore robot or spider traffic. This configuration should be placed in `config/initializers/split.rb`.
```ruby
Split.configure do |config|
config.robot_regex = /my_custom_robot_regex/
end
```
--------------------------------
### Configure Redis Namespace
Source: https://github.com/splitrb/split/wiki/Tutorial
Sets a namespace for Split's Redis keys to prevent key collisions with other applications or services using the same Redis instance. This utilizes the `redis-namespace` library.
```ruby
Split.redis.namespace = "split:blog"
```
--------------------------------
### Configure Split Framework Settings
Source: https://context7.com/splitrb/split/llms.txt
The `Split.configure` method allows setting global configuration options for the Split framework. This includes experiment behavior, Redis connection details, persistence strategies, algorithms, and event hooks.
```ruby
# Example configuration (this is a placeholder as the actual code was missing)
# Split.configure do |config|
# config.persistence = MyCustomPersistenceAdapter.new
# config.algorithm = :weighted_random
# config.redis = Redis.new(:host => 'localhost', :port => 6379)
# end
```
--------------------------------
### Configure Dual Persistence Adapters for Split Gem
Source: https://context7.com/splitrb/split/llms.txt
Implements a dual persistence strategy using both Redis for logged-in users and cookies for guests. It requires defining adapters for both states and specifying how to determine the user's logged-in status.
```ruby
# Dual adapter: Redis for logged-in, Cookie for guests
cookie_adapter = Split::Persistence::CookieAdapter
redis_adapter = Split::Persistence::RedisAdapter.with_config(
lookup_by: ->(context) { context.send(:current_user).try(:id) },
expire_seconds: 2592000
)
Split.configure do |config|
config.persistence = Split::Persistence::DualAdapter.with_config(
logged_in: ->(context) { !context.send(:current_user).try(:id).nil? },
logged_in_adapter: redis_adapter,
logged_out_adapter: cookie_adapter
)
config.persistence_cookie_length = 2592000
end
```
--------------------------------
### Define A/B Test with Multiple Alternatives
Source: https://github.com/splitrb/split/wiki/Tutorial
Defines an A/B test for link text with multiple alternatives. The first alternative is the control. More alternatives increase the time needed to reach statistical significance.
```erb
<%= link_to ab_test('link_text', 'Signup', 'Join', 'Become a member', 'Signin', 'Login'), signup_path %>
```
--------------------------------
### Implement Trial Lifecycle Callbacks
Source: https://context7.com/splitrb/split/llms.txt
Provides concrete implementations for event hooks defined in the Split configuration. These methods handle tracking user participation, new participant events, and conversion events using analytics services.
```ruby
# In ApplicationController
class ApplicationController < ActionController::Base
helper_method :track_participation, :track_new_participant, :track_conversion
def track_participation(trial)
Rails.logger.info(
"Trial participation - " \
"experiment: #{trial.experiment.name}, " \
"alternative: #{trial.alternative.name}, " \
"user: #{current_user&.id || session.id}"
)
end
def track_new_participant(trial)
Analytics.track(
user_id: current_user&.id,
event: "Experiment Started",
properties: {
experiment_name: trial.experiment.name,
alternative: trial.alternative.name,
metadata: trial.metadata
}
)
end
def track_conversion(trial)
Analytics.track(
user_id: current_user&.id,
event: "Experiment Converted",
properties: {
experiment_name: trial.experiment.name,
alternative: trial.alternative.name,
goals: trial.goals
}
)
# Send to data warehouse
DataWarehouse.record_conversion(
experiment: trial.experiment.name,
alternative: trial.alternative.name,
timestamp: Time.now
)
end
end
# Trial object properties available in hooks:
# - trial.experiment.name
# - trial.alternative.name
# - trial.metadata (hash)
# - trial.goals (array)
```
--------------------------------
### Define A/B Test in View
Source: https://github.com/splitrb/split/wiki/Tutorial
Defines an A/B test experiment named 'form_title' with two alternatives: 'Sign up now' (control) and 'Join Today'. The `ab_test` helper method is used in ERB views.
```erb
<%= ab_test('form_title', 'Sign up now', 'Join Today') %>
```
--------------------------------
### Configure Experiments with Hash and YAML in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Demonstrates how to configure experiments using a Ruby hash or by loading from a YAML file. This allows for centralized experiment definitions controlling alternatives, weights, algorithms, and reset behavior.
```ruby
Split.configure do |config|
config.experiments = {
my_first_experiment:
alternatives: ["a", "b"],
resettable: false
},
:my_second_experiment => {
algorithm: 'Split::Algorithms::Whiplash',
alternatives:
[
{ name: "a", percent: 67 },
{ name: "b", percent: 33 }
]
}
}
end
```
```ruby
Split.configure do |config|
config.experiments = YAML.load_file "config/experiments.yml"
end
```
--------------------------------
### Define Per-Experiment Algorithms and Alternatives
Source: https://context7.com/splitrb/split/llms.txt
Allows specifying different algorithms and alternatives for individual experiments. This provides flexibility in how each experiment is run, such as using Whiplash for one and BlockRandomization for another.
```ruby
Split.configure do |config|
config.experiments = {
aggressive_test: {
algorithm: "Split::Algorithms::Whiplash",
alternatives: ["a", "b", "c"]
},
balanced_test: {
algorithm: "Split::Algorithms::BlockRandomization",
alternatives: ["x", "y"]
}
}
end
```
--------------------------------
### Configure IP Address Exclusion
Source: https://github.com/splitrb/split/wiki/Tutorial
Configures Split to ignore visits from specific IP addresses to prevent skewing A/B test results. Add IP addresses to the `config.ignore_ip_addresses` array in `config/initializers/split.rb`.
```ruby
Split.configure do |config|
config.ignore_ip_addresses << '81.19.48.130'
end
```
--------------------------------
### Track Conversion Event with ab_finished
Source: https://github.com/splitrb/split/wiki/Tutorial
Marks a visitor as having reached the conversion point for an experiment. This method should typically be placed in your controller after a conversion event, such as user signup. Once a conversion is marked, the visitor's split session is reset.
```ruby
ab_finished('link_text')
```
--------------------------------
### Configure Redis Persistence Adapter for Split Gem
Source: https://context7.com/splitrb/split/llms.txt
Sets up the Redis adapter for persisting experiment assignments, suitable for logged-in users. It requires a way to look up the user (e.g., user ID) and can specify a namespace and expiration time.
```ruby
# Redis adapter for logged-in users
Split.configure do |config|
config.persistence = Split::Persistence::RedisAdapter.with_config(
lookup_by: ->(context) { context.current_user.id },
namespace: "split_users",
expire_seconds: 2592000
)
end
```
--------------------------------
### Mount Split Dashboard with Rack::URLMap
Source: https://github.com/splitrb/split/wiki/Tutorial
Integrates the Split dashboard into your Rack-based application using `Rack::URLMap`. This allows you to access the dashboard at a specified URL, separate from your main application. The dashboard provides an overview of experiment performance.
```ruby
require 'split/dashboard'
run Rack::URLMap.new \
"/" => Your::App.new,
"/split" => Split::Dashboard.new
```
--------------------------------
### Configure Combined Experiments in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Illustrates how to set up combined experiments in Ruby. This allows testing multiple independent experiments simultaneously, with a parent experiment controlling the group.
```ruby
Split.configuration.experiments = {
:button_color_experiment => {
:alternatives => ["blue", "green"],
:combined_experiments => ["button_color_on_signup", "button_color_on_login"]
}
}
```
--------------------------------
### Integrate Split Dashboard in Rails Routes
Source: https://github.com/splitrb/split/wiki/Tutorial
Mounts the Split dashboard within a Rails application's routes. This configuration allows the dashboard to be accessed at a defined path within your Rails application. Update your `Gemfile` to include the dashboard and then configure your routes.
```ruby
gem 'split', require: 'split/dashboard' # For ruby 1.8.*, :require => 'split/dashboard'
```
```ruby
Rails::Application.routes do
mount Split::Dashboard, at: 'split' # For ruby 1.8.*, :at => 'split'
end
```
--------------------------------
### Configure Combined Experiments
Source: https://context7.com/splitrb/split/llms.txt
Sets up an experiment that is tied to the completion of multiple other experiments. This allows for complex user journeys where success is defined by completing a sequence or set of actions across different tests.
```ruby
Split.configure do |config|
config.allow_multiple_experiments = true
config.experiments = {
button_color_experiment: {
alternatives: ["blue", "green"],
combined_experiments: ["button_color_on_signup", "button_color_on_login"]
}
}
end
ab_combined_test(:button_color_experiment)
ab_finished(:button_color_on_signup)
ab_finished(:button_color_on_login)
```
--------------------------------
### Secure Split Dashboard with Rack::Auth::Basic
Source: https://github.com/splitrb/split/wiki/Tutorial
Adds basic HTTP authentication to the Split dashboard mounted via Rack. This protects the dashboard from unauthorized access by requiring a username and password. Ensure you replace the placeholder credentials with your actual secure login details.
```ruby
Split::Dashboard.use Rack::Auth::Basic do |username, password|
username == 'admin' && password == 'p4s5w0rd'
end
```
--------------------------------
### Configure Event Hooks for Trial Lifecycle
Source: https://context7.com/splitrb/split/llms.txt
Registers callbacks to be executed at various stages of the experiment and trial lifecycle. These hooks allow for custom logic such as logging, analytics tracking, or data synchronization.
```ruby
# config/initializers/split.rb
Split.configure do |config|
# Fires on every trial (existing and new participants)
config.on_trial = :track_participation
# Fires only when new user enters experiment
config.on_trial_choose = :track_new_participant
# Fires when trial is completed
config.on_trial_complete = :track_conversion
# Experiment lifecycle
config.on_experiment_reset = ->(exp) { log_reset(exp) }
config.on_experiment_delete = ->(exp) { cleanup_data(exp) }
config.on_before_experiment_reset = ->(exp) { backup_data(exp) }
config.on_before_experiment_delete = ->(exp) { archive_results(exp) }
config.on_experiment_winner_choose = ->(exp) { notify_stakeholders(exp) }
end
```
--------------------------------
### Configure Experiments with Metadata in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Demonstrates adding metadata to experiment alternatives in Ruby. Metadata allows for associating additional data, like text or configuration options, with each alternative.
```ruby
Split.configure do |config|
config.experiments = {
my_first_experiment:
alternatives: ["a", "b"],
metadata:
"a" => {"text" => "Have a fantastic day"},
"b" => {"text" => "Don't get hit by a bus"}
}
}
end
```
--------------------------------
### Configure Split Algorithms for Alternative Selection
Source: https://context7.com/splitrb/split/llms.txt
Allows selection of different algorithms for choosing experiment alternatives, such as Weighted Sample (default), Whiplash (multi-armed bandit), or Block Randomization. Each algorithm offers a different strategy for traffic distribution based on weights, historical performance, or predefined blocks.
```ruby
# Weighted Sample (default) - Random selection based on weights
Split.configure do |config|
config.algorithm = Split::Algorithms::WeightedSample
end
ab_test(:button_test, {"control" => 70}, {"variant" => 30})
# 70% see control, 30% see variant (random but weighted)
# Whiplash - Multi-armed bandit that favors better performers
Split.configure do |config|
config.algorithm = Split::Algorithms::Whiplash
end
ab_test(:pricing_test, "low", "medium", "high")
# Automatically shifts traffic toward better converting alternatives
# Uses historical conversion data to optimize distribution
```
--------------------------------
### Implement Custom Adapter for Split Persistence
Source: https://context7.com/splitrb/split/llms.txt
Allows you to define a custom adapter for storing experiment data, such as user choices and experiment states. This custom adapter must implement specific methods like `initialize`, `[]`, `[]=`, `delete`, and `keys`. The `Split.configure` block is used to register this custom adapter.
```ruby
class MyCustomAdapter
def initialize(context)
@context = context
end
def [](key)
# Retrieve stored alternative for experiment key
end
def []=(key, value)
# Store alternative choice for experiment key
end
def delete(key)
# Remove experiment from storage
end
def keys
# Return all stored experiment keys
end
end
Split.configure do |config|
config.persistence = MyCustomAdapter
end
```
--------------------------------
### Enable Redis Caching in Split
Source: https://github.com/splitrb/split/blob/main/README.md
Enables Redis caching for Split (v4.0+) to reduce load in high-volume scenarios by caching static data like experiment catalog, start times, and winners.
```ruby
Split.configuration.cache = true
```
--------------------------------
### Configure Split Project Settings
Source: https://github.com/splitrb/split/blob/main/README.md
This Ruby code snippet illustrates how to configure various settings for the Split project. It covers enabling database failover, customizing error handling for database failures, allowing multiple experiments, controlling experiment reset behavior, and specifying a custom Redis connection URL.
```ruby
Split.configure do |config|
config.db_failover = true # handle Redis errors gracefully
config.db_failover_on_db_error = -> (error) { Rails.logger.error(error.message) }
config.allow_multiple_experiments = true
config.enabled = true
config.persistence = Split::Persistence::SessionAdapter
#config.start_manually = false ## new test will have to be started manually from the admin panel. default false
#config.reset_manually = false ## if true, it never resets the experiment data, even if the configuration changes
config.include_rails_helper = true
config.redis = "redis://custom.redis.url:6380"
end
```
--------------------------------
### Using Experiments and Metadata in ERB Views
Source: https://github.com/splitrb/split/blob/main/README.md
Illustrates how to integrate Split.rb experiments and their metadata directly within ERB templates. This allows for conditional rendering and dynamic content display based on experiment outcomes.
```erb
<% ab_test("my_first_experiment") do |alternative, meta| %>
<%= alternative %>
<%= meta['text'] %>
<% end %>
```
--------------------------------
### Configure Default Experiment Algorithm Globally
Source: https://github.com/splitrb/split/blob/main/README.md
Demonstrates how to set a global default algorithm for all Split experiments using the `Split.configure` block. This allows for consistent algorithm selection across the application.
```ruby
Split.configure do |config|
config.algorithm = Split::Algorithms::Whiplash
end
```
--------------------------------
### Define Multiple Goals for an Experiment
Source: https://context7.com/splitrb/split/llms.txt
Enables an experiment to track multiple conversion goals. Each goal can represent a different user action, allowing for comprehensive analysis of experiment impact on various conversion events.
```ruby
Split.configure do |config|
config.experiments = {
product_page: {
alternatives: ["design_a", "design_b"],
goals: ["add_to_cart", "purchase", "wishlist"]
}
}
end
```
--------------------------------
### Configure Trial Event Hooks in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Shows how to set up callback methods that are triggered during experiment trials. These hooks can be used for logging or other actions when a user participates in a trial, when a new user is chosen for a trial, or when a trial is completed. The methods receive a Trial instance as an argument.
```ruby
Split.configure do |config|
config.on_trial = :log_trial # run on every trial
config.on_trial_choose = :log_trial_choose # run on trials with new users only
config.on_trial_complete = :log_trial_complete
end
```
--------------------------------
### Complete a Specific Experiment Goal
Source: https://github.com/splitrb/split/blob/main/README.md
Demonstrates how to record the completion of a specific goal for an experiment. This allows tracking distinct conversion events associated with different experiment alternatives.
```ruby
ab_finished(link_color: "purchase")
```
--------------------------------
### Configure Block Randomization Algorithm
Source: https://context7.com/splitrb/split/llms.txt
Configures Split to use the BlockRandomization algorithm globally, ensuring an equal split between alternatives for all experiments. This is useful when perfect sample size balance is required.
```ruby
Split.configure do |config|
config.algorithm = Split::Algorithms::BlockRandomization
end
```
--------------------------------
### Configure Redis Connection for Split Gem
Source: https://context7.com/splitrb/split/llms.txt
Sets up the Redis connection for the Split gem. It can use a direct connection string or reuse an existing Redis connection. Failover options and error handling are also configurable.
```ruby
Split.configure do |config|
# Redis connection
config.redis = "redis://localhost:6379"
# Or reuse existing connection:
# config.redis = $redis
# Enable Redis failover (return control alternative on error)
config.db_failover = true
config.db_failover_on_db_error = ->(error) { Rails.logger.error(error.message) }
# Allow users in multiple experiments simultaneously
config.allow_multiple_experiments = true
# Use cookie persistence instead of session
config.persistence = :cookie
config.persistence_cookie_length = 2592000 # 30 days
# Use Redis persistence for logged-in users
# config.persistence = Split::Persistence::RedisAdapter.with_config(
# lookup_by: ->(context) { context.current_user_id },
# expire_seconds: 2592000
# )
# Set algorithm (WeightedSample, Whiplash, BlockRandomization)
config.algorithm = Split::Algorithms::Whiplash
# Trial event hooks
config.on_trial = :log_trial
config.on_trial_choose = :log_new_participant
config.on_trial_complete = :log_conversion
# Experiment lifecycle hooks
config.on_experiment_reset = ->(exp) { Rails.logger.info("Reset: #{exp.name}") }
config.on_experiment_delete = ->(exp) { cleanup_analytics(exp) }
config.on_experiment_winner_choose = ->(exp) { notify_team(exp) }
# Bot filtering
config.robot_regex = /bot|crawler|spider/i
config.bots["CustomBot"] = "Our custom bot description"
# IP filtering
config.ignore_ip_addresses << "192.168.1.1"
config.ignore_ip_addresses << /10\.0\.0\.[0-9]+/
# Statistical settings
config.winning_alternative_recalculation_interval = 3600 # 1 hour
config.beta_probability_simulations = 10000
# Manual experiment control
config.start_manually = false
config.reset_manually = false
# Enable Redis caching for experiment lookups
config.cache = true
end
```
--------------------------------
### Mock Experiments for RSpec Testing
Source: https://context7.com/splitrb/split/llms.txt
Illustrates the use of RSpec helpers to control experiment outcomes during testing. This allows developers to force specific alternatives for A/B tests without executing the actual randomization logic.
```ruby
# Example usage in an RSpec test:
describe "My Feature" do
it "shows the correct content based on experiment"
# Force the user into the 'new_design' alternative for the 'homepage_layout' experiment
allow(Split::ExperimentCache).to receive(:find).and_return(instance_double(Split::Experiment, name: 'homepage_layout', winner: nil, control: nil))
allow(view).to receive(:experiment_is_enabled?).with('homepage_layout', 'new_design').and_return(true)
render_template
expect(rendered).to include("New Design Content")
end
end
```
--------------------------------
### Configure Custom Persistence Adapter in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Demonstrates how to configure split.rb to use a custom class for persistence. Your custom adapter must implement the same API as existing adapters like CookieAdapter or SessionAdapter. This allows for flexible data storage solutions.
```ruby
Split.configure do |config|
config.persistence = YourCustomAdapterClass
end
```
--------------------------------
### Load Split Configuration from YAML
Source: https://github.com/splitrb/split/blob/main/README.md
Shows how to load Split's Redis configuration from a YAML file, typically in a Rails initializer. This approach allows environment-specific Redis settings to be managed separately.
```ruby
split_config = YAML.load_file(Rails.root.join('config', 'split.yml'))
Split.redis = split_config[Rails.env]
```
--------------------------------
### Complete Goal with Additional Options
Source: https://github.com/splitrb/split/blob/main/README.md
Shows how to pass additional options, such as `reset: false`, when finishing a specific experiment goal. This allows fine-grained control over experiment behavior upon goal completion.
```ruby
ab_finished({ link_color: "purchase" }, reset: false)
```
--------------------------------
### Track Specific Goals within an Experiment
Source: https://context7.com/splitrb/split/llms.txt
Demonstrates how to record the completion of specific goals within an experiment. The `ab_finished` method is called with the experiment name and the specific goal to be tracked.
```ruby
# Track add to cart goal
def add_to_cart
@cart.add_item(params[:product_id])
ab_finished({product_page: "add_to_cart"})
end
# Track purchase goal
def complete_purchase
process_payment
ab_finished({product_page: "purchase"})
end
# Track wishlist goal
def add_to_wishlist
current_user.wishlist.add(params[:product_id])
ab_finished({product_page: "wishlist"})
end
```
--------------------------------
### Use Split Programmatic API Outside Web Context
Source: https://context7.com/splitrb/split/llms.txt
Provides a way to use Split's core objects directly for managing experiments outside of typical web request cycles, such as in CLI scripts, background jobs, or API endpoints. It demonstrates creating experiments, users, trials, choosing alternatives, completing trials, and tracking conversions.
```ruby
# Create experiment programmatically
experiment = Split::ExperimentCatalog.find_or_create(
"email_subject_test",
"Subject A",
"Subject B",
"Subject C"
)
# Create user and trial
user = Split::User.find("user_12345", :redis)
trial = Split::Trial.new(user: user, experiment: experiment)
# Choose alternative
trial.choose!
alternative = trial.alternative.name # => "Subject A"
# Use alternative in your code
case alternative
when "Subject A"
subject = "Limited Time Offer - 50% Off"
when "Subject B"
subject = "Your Exclusive Discount Inside"
when "Subject C"
subject = "Don't Miss Out - Sale Ends Soon"
end
# Send email with chosen subject
UserMailer.promotional_email(user, subject: subject).deliver_later
# Track conversion when user opens or clicks
if email_clicked?
trial.complete!
end
# Background job example
class RecommendationJob < ApplicationJob
def perform(user_id)
experiment = Split::ExperimentCatalog.find_or_create(
"recommendation_algorithm",
"collaborative",
"content_based"
)
user = Split::User.find(user_id, :redis)
trial = Split::Trial.new(user: user, experiment: experiment)
algorithm = trial.choose!.name
recommendations = calculate_recommendations(user_id, algorithm)
# Track if user clicks any recommendation
if recommendations.any?(&:clicked?)
trial.complete!
end
end
end
```
--------------------------------
### Track Conversions Using Custom Metrics
Source: https://github.com/splitrb/split/blob/main/README.md
Demonstrates how to mark an experiment completion using a custom metric name instead of the experiment identifier. This is useful when multiple experiments share the same conversion goal.
```ruby
ab_finished(:my_metric)
```
--------------------------------
### Run A/B Test in Controller
Source: https://github.com/splitrb/split/blob/main/README.md
Shows how to initiate an A/B test within a controller action using the `ab_test` method. It assigns one of the alternatives ('100', '200', '300' free points) to an instance variable for use in the view.
```ruby
def register_new_user
# See what level of free points maximizes users' decision to buy replacement points.
@starter_points = ab_test(:new_user_free_points, '100', '200', '300')
end
```
--------------------------------
### Configure Experiment Hooks in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Demonstrates setting up callback procs for experiment lifecycle events like reset, delete, and winner selection. These hooks are useful for maintaining data consistency by performing related actions in your application when experiments are modified or finalized.
```ruby
Split.configure do |config|
# after experiment reset or deleted
config.on_experiment_reset = -> (example) { # Do something on reset }
config.on_experiment_delete = -> (experiment) { # Do something else on delete }
# before experiment reset or deleted
config.on_before_experiment_reset = -> (example) { # Do something on reset }
config.on_before_experiment_delete = -> (experiment) { # Do something else on delete }
# after experiment winner had been set
config.on_experiment_winner_choose = -> (experiment) { # Do something on winner choose }
end
```
--------------------------------
### Configure Cookie Persistence Adapter for Split Gem
Source: https://context7.com/splitrb/split/llms.txt
Configures the Split gem to use cookies for persistence. This allows experiment assignments to persist across sessions and can be configured with an expiration length and domain.
```ruby
# Cookie adapter
Split.configure do |config|
config.persistence = :cookie
config.persistence_cookie_length = 2592000 # 30 days
config.persistence_cookie_domain = ".example.com" # Share across subdomains
end
```
--------------------------------
### Configure Experiments with Metrics in Ruby
Source: https://github.com/splitrb/split/blob/main/README.md
Shows how to associate a custom metric with an experiment in Ruby. This allows tracking conversions using a named metric instead of the experiment name, enabling reuse across experiments.
```ruby
Split.configure do |config|
config.experiments = {
my_first_experiment:
alternatives: ["a", "b"],
metric: :my_metric
}
}
end
```
--------------------------------
### Define Experiments in YAML File
Source: https://github.com/splitrb/split/blob/main/README.md
Shows the structure for defining experiments in a YAML file, including alternatives, percentages, and reset settings. This format is loaded by Split.rb for experiment configuration.
```yaml
my_first_experiment:
alternatives:
- a
- b
my_second_experiment:
alternatives:
- name: a
percent: 67
- name: b
percent: 33
resettable: false
```
--------------------------------
### Allow Multiple Experiments
Source: https://github.com/splitrb/split/blob/main/README.md
Configure Split to allow users to participate in multiple experiments concurrently. By default, users are limited to one experiment at a time to avoid skewed results.
```ruby
Split.configure do |config|
config.allow_multiple_experiments = true
end
```
--------------------------------
### Define Experiment Metadata in YAML
Source: https://github.com/splitrb/split/blob/main/README.md
Shows how to define experiment metadata within a YAML configuration file. This allows associating rich data with experiment alternatives, which can be accessed in code or views.
```yaml
my_first_experiment:
alternatives:
- a
- b
metadata:
a:
text: "Have a fantastic day"
b:
text: "Don't get hit by a bus"
```
--------------------------------
### Configure Session Persistence Adapter for Split Gem
Source: https://context7.com/splitrb/split/llms.txt
Sets the Split gem to use the session adapter for persisting user experiment assignments. This is the default behavior and stores assignments within the user's session.
```ruby
# Session adapter (default)
Split.configure do |config|
config.persistence = Split::Persistence::SessionAdapter
end
```
--------------------------------
### Proxy Caching with Split Etag
Source: https://github.com/splitrb/split/wiki/Caching
Demonstrates how to use the Split gem with proxy caching by including the A/B test alternative in the Etag generation. This prevents incorrect caching for users on different alternatives. It requires the Split gem and assumes a controller action context.
```ruby
response.etag = @etag = [
User.find(params[:id]),
ab_test('user_page', 'old', 'new')
]
if request.fresh?(response)
head :not_modified
else
render :action => 'index'
end
```
--------------------------------
### Track Conversion with ab_finished
Source: https://context7.com/splitrb/split/llms.txt
The `ab_finished` method marks the completion of a goal for an experiment, incrementing the conversion count for the user's assigned alternative. It can track specific goals, prevent resetting the user's alternative on revisit, and handle multiple goals.
```ruby
class PurchaseController < ApplicationController
def create
@purchase = Purchase.create(purchase_params)
if @purchase.persisted?
# Track that user converted on the pricing experiment
ab_finished(:pricing_layout)
# Can also track from view:
# <% ab_finished(:checkout_flow_redesign) %>
redirect_to thank_you_path
end
end
end
# Complete without resetting user (keeps same alternative on revisit)
def subscribe
subscription = Subscription.create(user: current_user, plan: params[:plan])
ab_finished(:subscription_flow, reset: false)
# User will always see the same alternative in future visits
end
# Complete experiment with specific goal
def purchase
create_purchase
ab_finished({pricing_experiment: "purchase"})
# Completes the "purchase" goal for pricing_experiment
end
# Complete with multiple goals defined
def checkout
process_payment
ab_finished({:checkout_flow => "payment_completed"}, reset: false)
end
```
--------------------------------
### Mount Split Dashboard for Web Interface
Source: https://context7.com/splitrb/split/llms.txt
Integrates the Split dashboard into your web application to monitor experiments, view statistics, and manage the experiment lifecycle. This snippet shows how to mount the dashboard in Rails and Sinatra applications, including options for basic and Devise/Warden authentication.
```ruby
# Rails: config/routes.rb
Rails.application.routes.draw do
mount Split::Dashboard, at: "split"
end
# Access at: http://localhost:3000/split
# With basic authentication
# config/initializers/split.rb
Split::Dashboard.use Rack::Auth::Basic do |username, password|
ActiveSupport::SecurityUtils.secure_compare(
::Digest::SHA256.hexdigest(username),
::Digest::SHA256.hexdigest(ENV["SPLIT_USERNAME"])
) & ActiveSupport::SecurityUtils.secure_compare(
::Digest::SHA256.hexdigest(password),
::Digest::SHA256.hexdigest(ENV["SPLIT_PASSWORD"])
)
end
# With Devise/Warden authentication
match "/split" => Split::Dashboard,
anchor: false,
via: [:get, :post, :delete],
constraints: ->(request) do
request.env["warden"].authenticated?
request.env["warden"].authenticate!
end
# Sinatra: config.ru
require "split/dashboard"
run Rack::URLMap.new(
"/" => MySinatraApp.new,
"/split" => Split::Dashboard.new
)
```
--------------------------------
### Complete A/B Test Experiment with Redis Persistence - Ruby
Source: https://github.com/splitrb/split/wiki/Use-Split-outside-a-web-request
This Ruby code snippet shows how to mark an A/B test experiment as completed after a user has made a decision. It re-initializes the user and experiment context and then calls `complete!` on the trial object. Note that `choose!` might need to be called again if the trial's alternative is not retained.
```ruby
# Finish the test for an object
experiment_name = 'my_experience'
key = "thing-#{thing.id}"
ab_user = Split::User.new(nil, Split::Persistence::RedisAdapter.new(nil, key))
experiment = Split::ExperimentCatalog.find_or_create(experiment_name, 'variant_A', 'variant_B')
trial = Split::Trial.new(user: ab_user, experiment: experiment)
trial.choose!
trial.complete!
```
--------------------------------
### Use Shared Metrics Across Experiments
Source: https://context7.com/splitrb/split/llms.txt
Configures multiple experiments to share a single metric for conversion tracking. This is useful when a common outcome, like user signup, signifies success for different A/B tests.
```ruby
Split.configure do |config|
config.experiments = {
homepage_hero: {
alternatives: ["video", "image", "carousel"],
metric: :user_signup
},
navigation_style: {
alternatives: ["top_bar", "sidebar", "hamburger"],
metric: :user_signup
}
}
end
# Completes both experiments when user signs up
def create_user
@user = User.create(user_params)
ab_finished(:user_signup) # Completes both experiments
end
```