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