Class: TestTrack::Visitor

Inherits:
Object
  • Object
show all
Includes:
RequiredOptions
Defined in:
app/models/test_track/visitor.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Visitor

Returns a new instance of Visitor.



6
7
8
9
10
11
12
13
14
15
# File 'app/models/test_track/visitor.rb', line 6

def initialize(opts = {})
  opts = opts.dup
  @id = opts.delete(:id)
  @assignments = opts.delete(:assignments)
  unless id
    @id = SecureRandom.uuid
    @assignments ||= [] # If we're generating a visitor, we don't need to fetch the assignments
  end
  raise "unknown opts: #{opts.keys.to_sentence}" if opts.present?
end

Instance Attribute Details

#idObject (readonly)

Returns the value of attribute id.



4
5
6
# File 'app/models/test_track/visitor.rb', line 4

def id
  @id
end

Class Method Details

.backfill_identity(opts) ⇒ Object



82
83
84
85
86
87
88
89
90
91
# File 'app/models/test_track/visitor.rb', line 82

def self.backfill_identity(opts)
  remote_identifier_visitor = TestTrack::Remote::Visitor.from_identifier(opts[:identifier_type], opts[:identifier_value])
  visitor = new(
    id: remote_identifier_visitor.id,
    assignments: remote_identifier_visitor.assignments
  )

  TestTrack::CreateAliasJob.new(existing_id: opts[:existing_id], alias_id: visitor.id).perform
  visitor
end

Instance Method Details

#ab(split_name, opts = {}) ⇒ Object

rubocop:disable Metrics/MethodLength, Metrics/AbcSize



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'app/models/test_track/visitor.rb', line 29

def ab(split_name, opts = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
  opts = opts.dup
  split_name = split_name.to_s
  true_variant = opts.delete(:true_variant)
  context = require_option!(opts, :context)
  raise "unknown opts: #{opts.keys.to_sentence}" if opts.present?

  ab_configuration = TestTrack::ABConfiguration.new split_name: split_name, true_variant: true_variant, split_registry: split_registry

  vary(split_name, context: context) do |v|
    v.when ab_configuration.variants[:true] do
      true
    end
    v.default ab_configuration.variants[:false] do
      false
    end
  end
end

#assignment_jsonObject



58
59
60
61
62
# File 'app/models/test_track/visitor.rb', line 58

def assignment_json
  assignment_registry.values.each_with_object({}) do |assignment, hsh|
    hsh[assignment.split_name] = assignment.variant
  end
end

#assignment_registryObject



48
49
50
51
52
# File 'app/models/test_track/visitor.rb', line 48

def assignment_registry
  @assignment_registry ||= assignments.each_with_object({}) do |assignment, hsh|
    hsh[assignment.split_name] = assignment
  end
end

#id_overridden_by_existing_visitor?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'app/models/test_track/visitor.rb', line 101

def id_overridden_by_existing_visitor?
  @id_overridden_by_existing_visitor || false
end


68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'app/models/test_track/visitor.rb', line 68

def link_identifier!(identifier_type, identifier_value)
  identifier_opts = { identifier_type: identifier_type, visitor_id: id, value: identifier_value.to_s }
  begin
    identifier = TestTrack::Remote::Identifier.create!(identifier_opts)
    merge!(identifier.visitor)
  rescue *TestTrack::SERVER_ERRORS => e
    Rails.logger.error "TestTrack failed to link identifier, retrying. #{e}"

    # If at first you don't succeed, async it - we may not display 100% consistent UX this time,
    # but subsequent requests will be better off
    TestTrack::Remote::Identifier.delay.create!(identifier_opts)
  end
end

#loaded?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'app/models/test_track/visitor.rb', line 97

def loaded?
  !offline? && @remote_visitor.present?
end

#offline?Boolean

Returns:

  • (Boolean)


93
94
95
# File 'app/models/test_track/visitor.rb', line 93

def offline?
  @tt_offline
end

#split_registryObject



64
65
66
# File 'app/models/test_track/visitor.rb', line 64

def split_registry
  @split_registry ||= TestTrack::Remote::SplitRegistry.to_hash
end

#unsynced_assignmentsObject



54
55
56
# File 'app/models/test_track/visitor.rb', line 54

def unsynced_assignments
  @unsynced_assignments ||= assignment_registry.values.select(&:unsynced?)
end

#vary(split_name, opts = {}) {|v| ... } ⇒ Object

Yields:

  • (v)

Raises:

  • (ArgumentError)


17
18
19
20
21
22
23
24
25
26
27
# File 'app/models/test_track/visitor.rb', line 17

def vary(split_name, opts = {})
  opts = opts.dup
  split_name = split_name.to_s
  context = require_option!(opts, :context)
  raise "unknown opts: #{opts.keys.to_sentence}" if opts.present?

  raise ArgumentError, "must provide block to `vary` for #{split_name}" unless block_given?
  v = TestTrack::VaryDSL.new(assignment: assignment_for(split_name), context: context, split_registry: split_registry)
  yield v
  v.send :run
end