lib/field_test/experiment.rb in field_test-0.2.0 vs lib/field_test/experiment.rb in field_test-0.2.1

- old
+ new

@@ -1,8 +1,8 @@ module FieldTest class Experiment - attr_reader :id, :name, :description, :variants, :weights, :winner, :started_at, :ended_at + attr_reader :id, :name, :description, :variants, :weights, :winner, :started_at, :ended_at, :goals def initialize(attributes) attributes = attributes.symbolize_keys @id = attributes[:id] @name = attributes[:name] || @id.to_s.titleize @@ -10,10 +10,12 @@ @variants = attributes[:variants] @weights = @variants.size.times.map { |i| attributes[:weights].to_a[i] || 1 } @winner = attributes[:winner] @started_at = Time.zone.parse(attributes[:started_at].to_s) if attributes[:started_at] @ended_at = Time.zone.parse(attributes[:ended_at].to_s) if attributes[:ended_at] + @goals = attributes[:goals] || ["conversion"] + @use_events = attributes[:use_events] end def variant(participants, options = {}) return winner if winner return variants.first if options[:exclude] @@ -51,33 +53,70 @@ end membership.try(:variant) || variants.first end - def convert(participants) + def convert(participants, goal: nil) + goal ||= goals.first + participants = FieldTest::Participant.standardize(participants) check_participants(participants) membership = membership_for(participants) if membership - membership.converted = true - membership.save! if membership.changed? + if membership.respond_to?(:converted) + membership.converted = true + membership.save! if membership.changed? + end + + if use_events? + FieldTest::Event.create!( + name: goal, + field_test_membership_id: membership.id + ) + end + true else false end end def memberships FieldTest::Membership.where(experiment: id) end - def results - data = memberships.group(:variant).group(:converted) - data = data.where("created_at >= ?", started_at) if started_at - data = data.where("created_at <= ?", ended_at) if ended_at - data = data.count + def events + FieldTest::Event.joins(:field_test_membership).where(field_test_memberships: {experiment: id}) + end + + def multiple_goals? + goals.size > 1 + end + + def results(goal: nil) + goal ||= goals.first + + relation = memberships.group(:variant) + relation = relation.where("created_at >= ?", started_at) if started_at + relation = relation.where("created_at <= ?", ended_at) if ended_at + + if use_events? + data = {} + sql = + relation.joins("LEFT JOIN field_test_events ON field_test_events.field_test_membership_id = field_test_memberships.id") + .select("variant, COUNT(DISTINCT participant) AS participated, COUNT(DISTINCT field_test_membership_id) AS converted") + .where(field_test_events: {name: goal}) + + FieldTest::Membership.connection.select_all(sql).each do |row| + data[[row["variant"], true]] = row["converted"].to_i + data[[row["variant"], false]] = row["participated"].to_i - row["converted"].to_i + end + else + data = relation.group(:converted).count + end + results = {} variants.each do |variant| converted = data[[variant, true]].to_i participated = converted + data[[variant, false]].to_i results[variant] = { @@ -123,9 +162,17 @@ results end def active? !winner + end + + def use_events? + if @use_events.nil? + FieldTest.events_supported? + else + @use_events + end end def self.find(id) experiment = all.index_by(&:id)[id.to_s] raise FieldTest::ExperimentNotFound unless experiment