Class: RailsOnboarding::AnalyticsEvent

Inherits:
ApplicationRecord show all
Defined in:
app/models/rails_onboarding/analytics_event.rb

Constant Summary collapse

ONBOARDING_STARTED =

Event types

"onboarding_started".freeze
ONBOARDING_STEP_STARTED =
"onboarding_step_started".freeze
ONBOARDING_STEP_COMPLETED =
"onboarding_step_completed".freeze
ONBOARDING_STEP_SKIPPED =
"onboarding_step_skipped".freeze
ONBOARDING_COMPLETED =
"onboarding_completed".freeze
ONBOARDING_SKIPPED =
"onboarding_skipped".freeze
TOOLTIP_SHOWN =
"tooltip_shown".freeze
TOOLTIP_DISMISSED =
"tooltip_dismissed".freeze
TOOLTIP_CLICKED =
"tooltip_clicked".freeze
MILESTONE_ACHIEVED =
"milestone_achieved".freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.track_custom_event(user:, event_name:, event_data: {}, session_id: nil) ⇒ Object



159
160
161
162
163
164
165
166
# File 'app/models/rails_onboarding/analytics_event.rb', line 159

def self.track_custom_event(user:, event_name:, event_data: {}, session_id: nil)
  track_event(
    user: user,
    event_type: event_name,
    properties: event_data,
    session_id: session_id
  )
end

.track_event(user:, event_type:, properties: {}, session_id: nil) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'app/models/rails_onboarding/analytics_event.rb', line 45

def self.track_event(user:, event_type:, properties: {}, session_id: nil)
  return unless RailsOnboarding.configuration.enable_analytics
  return unless table_exists?

  create!(
    user: user,
    event_type: event_type,
    properties: properties,
    session_id: session_id,
    occurred_at: Time.current
  )
rescue ActiveRecord::StatementInvalid => e
  # Gracefully handle missing table - analytics is optional
  Rails.logger.warn "RailsOnboarding Analytics: #{e.message}" if defined?(Rails)
  nil
end

.track_milestone_achieved(user:, milestone_key:, points_earned:, session_id: nil) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
# File 'app/models/rails_onboarding/analytics_event.rb', line 146

def self.track_milestone_achieved(user:, milestone_key:, points_earned:, session_id: nil)
  track_event(
    user: user,
    event_type: MILESTONE_ACHIEVED,
    properties: {
      milestone_key: milestone_key,
      points_earned: points_earned,
      total_points: user.total_milestone_points
    },
    session_id: session_id
  )
end

.track_onboarding_completed(user:, completion_time: nil, was_skipped: false, session_id: nil) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
# File 'app/models/rails_onboarding/analytics_event.rb', line 114

def self.track_onboarding_completed(user:, completion_time: nil, was_skipped: false, session_id: nil)
  track_event(
    user: user,
    event_type: was_skipped ? ONBOARDING_SKIPPED : ONBOARDING_COMPLETED,
    properties: {
      completion_time_seconds: completion_time,
      was_skipped: was_skipped,
      total_steps: RailsOnboarding.configuration.total_steps
    },
    session_id: session_id
  )
end

.track_onboarding_started(user:, session_id: nil) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'app/models/rails_onboarding/analytics_event.rb', line 62

def self.track_onboarding_started(user:, session_id: nil)
  track_event(
    user: user,
    event_type: ONBOARDING_STARTED,
    properties: {
      user_created_at: user.created_at,
      total_steps: RailsOnboarding.configuration.total_steps
    },
    session_id: session_id
  )
end

.track_step_completed(user:, step_name:, step_index:, time_spent: nil, session_id: nil) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'app/models/rails_onboarding/analytics_event.rb', line 87

def self.track_step_completed(user:, step_name:, step_index:, time_spent: nil, session_id: nil)
  track_event(
    user: user,
    event_type: ONBOARDING_STEP_COMPLETED,
    properties: {
      step_name: step_name,
      step_index: step_index,
      time_spent_seconds: time_spent,
      progress_percentage: user.onboarding_progress
    },
    session_id: session_id
  )
end

.track_step_skipped(user:, step_name:, step_index:, session_id: nil) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
# File 'app/models/rails_onboarding/analytics_event.rb', line 101

def self.track_step_skipped(user:, step_name:, step_index:, session_id: nil)
  track_event(
    user: user,
    event_type: ONBOARDING_STEP_SKIPPED,
    properties: {
      step_name: step_name,
      step_index: step_index,
      progress_percentage: user.onboarding_progress
    },
    session_id: session_id
  )
end

.track_step_started(user:, step_name:, step_index:, session_id: nil) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
# File 'app/models/rails_onboarding/analytics_event.rb', line 74

def self.track_step_started(user:, step_name:, step_index:, session_id: nil)
  track_event(
    user: user,
    event_type: ONBOARDING_STEP_STARTED,
    properties: {
      step_name: step_name,
      step_index: step_index,
      progress_percentage: user.onboarding_progress
    },
    session_id: session_id
  )
end

.track_tooltip_interaction(user:, tooltip_feature:, action:, session_id: nil) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'app/models/rails_onboarding/analytics_event.rb', line 127

def self.track_tooltip_interaction(user:, tooltip_feature:, action:, session_id: nil)
  event_type = case action.to_s
  when "shown" then TOOLTIP_SHOWN
  when "dismissed" then TOOLTIP_DISMISSED
  when "clicked" then TOOLTIP_CLICKED
  else "tooltip_interaction"
  end

  track_event(
    user: user,
    event_type: event_type,
    properties: {
      tooltip_feature: tooltip_feature,
      action: action
    },
    session_id: session_id
  )
end

Instance Method Details

#user=(user_instance) ⇒ Object

Rails 8 compatibility: Handle polymorphic associations gracefully



8
9
10
11
12
13
14
15
16
17
18
19
# File 'app/models/rails_onboarding/analytics_event.rb', line 8

def user=(user_instance)
  if user_instance
    klass = user_instance.class
    unless klass.respond_to?(:has_query_constraints?)
      klass.define_singleton_method(:has_query_constraints?) { false }
    end
    unless klass.respond_to?(:composite_primary_key?)
      klass.define_singleton_method(:composite_primary_key?) { false }
    end
  end
  super(user_instance)
end