ahoy_matey 1.5.5 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +184 -34
  3. data/CONTRIBUTING.md +42 -0
  4. data/LICENSE.txt +1 -1
  5. data/README.md +464 -407
  6. data/app/controllers/ahoy/base_controller.rb +23 -15
  7. data/app/controllers/ahoy/events_controller.rb +8 -2
  8. data/app/controllers/ahoy/visits_controller.rb +8 -1
  9. data/app/jobs/ahoy/geocode_job.rb +11 -0
  10. data/app/jobs/ahoy/geocode_v2_job.rb +31 -0
  11. data/config/routes.rb +1 -1
  12. data/lib/ahoy/base_store.rb +101 -0
  13. data/lib/ahoy/controller.rb +23 -16
  14. data/lib/ahoy/database_store.rb +94 -0
  15. data/lib/ahoy/engine.rb +14 -7
  16. data/lib/ahoy/helper.rb +40 -0
  17. data/lib/ahoy/model.rb +5 -27
  18. data/lib/ahoy/query_methods.rb +88 -0
  19. data/lib/ahoy/tracker.rb +105 -51
  20. data/lib/ahoy/utils.rb +7 -0
  21. data/lib/ahoy/version.rb +1 -1
  22. data/lib/ahoy/visit_properties.rb +99 -37
  23. data/lib/ahoy.rb +83 -93
  24. data/lib/ahoy_matey.rb +1 -1
  25. data/lib/generators/ahoy/activerecord_generator.rb +67 -0
  26. data/lib/generators/ahoy/base_generator.rb +13 -0
  27. data/lib/generators/ahoy/install_generator.rb +44 -0
  28. data/lib/generators/ahoy/mongoid_generator.rb +16 -0
  29. data/lib/generators/ahoy/templates/active_record_event_model.rb.tt +10 -0
  30. data/lib/generators/ahoy/templates/active_record_migration.rb.tt +62 -0
  31. data/lib/generators/ahoy/templates/active_record_visit_model.rb.tt +6 -0
  32. data/lib/generators/ahoy/templates/base_store_initializer.rb.tt +25 -0
  33. data/lib/generators/ahoy/templates/database_store_initializer.rb.tt +10 -0
  34. data/lib/generators/ahoy/{stores/templates/mongoid_event_model.rb → templates/mongoid_event_model.rb.tt} +4 -2
  35. data/lib/generators/ahoy/{stores/templates/mongoid_visit_model.rb → templates/mongoid_visit_model.rb.tt} +15 -9
  36. data/vendor/assets/javascripts/ahoy.js +271 -133
  37. metadata +37 -273
  38. data/.gitignore +0 -17
  39. data/Gemfile +0 -6
  40. data/Rakefile +0 -8
  41. data/ahoy_matey.gemspec +0 -38
  42. data/lib/ahoy/deckhands/location_deckhand.rb +0 -49
  43. data/lib/ahoy/deckhands/request_deckhand.rb +0 -52
  44. data/lib/ahoy/deckhands/technology_deckhand.rb +0 -47
  45. data/lib/ahoy/deckhands/traffic_source_deckhand.rb +0 -22
  46. data/lib/ahoy/deckhands/utm_parameter_deckhand.rb +0 -23
  47. data/lib/ahoy/geocode_job.rb +0 -13
  48. data/lib/ahoy/logger_silencer.rb +0 -75
  49. data/lib/ahoy/properties.rb +0 -58
  50. data/lib/ahoy/stores/active_record_store.rb +0 -61
  51. data/lib/ahoy/stores/active_record_token_store.rb +0 -114
  52. data/lib/ahoy/stores/base_store.rb +0 -88
  53. data/lib/ahoy/stores/bunny_store.rb +0 -33
  54. data/lib/ahoy/stores/fluentd_store.rb +0 -17
  55. data/lib/ahoy/stores/kafka_store.rb +0 -40
  56. data/lib/ahoy/stores/kinesis_firehose_store.rb +0 -42
  57. data/lib/ahoy/stores/log_store.rb +0 -53
  58. data/lib/ahoy/stores/mongoid_store.rb +0 -63
  59. data/lib/ahoy/stores/nats_store.rb +0 -34
  60. data/lib/ahoy/stores/nsq_store.rb +0 -36
  61. data/lib/ahoy/subscribers/active_record.rb +0 -19
  62. data/lib/ahoy/throttle.rb +0 -17
  63. data/lib/generators/ahoy/stores/active_record_events_generator.rb +0 -53
  64. data/lib/generators/ahoy/stores/active_record_generator.rb +0 -16
  65. data/lib/generators/ahoy/stores/active_record_visits_generator.rb +0 -43
  66. data/lib/generators/ahoy/stores/bunny_generator.rb +0 -15
  67. data/lib/generators/ahoy/stores/custom_generator.rb +0 -15
  68. data/lib/generators/ahoy/stores/fluentd_generator.rb +0 -15
  69. data/lib/generators/ahoy/stores/kafka_generator.rb +0 -15
  70. data/lib/generators/ahoy/stores/kinesis_firehose_generator.rb +0 -15
  71. data/lib/generators/ahoy/stores/log_generator.rb +0 -15
  72. data/lib/generators/ahoy/stores/mongoid_events_generator.rb +0 -19
  73. data/lib/generators/ahoy/stores/mongoid_generator.rb +0 -14
  74. data/lib/generators/ahoy/stores/mongoid_visits_generator.rb +0 -27
  75. data/lib/generators/ahoy/stores/nats_generator.rb +0 -15
  76. data/lib/generators/ahoy/stores/nsq_generator.rb +0 -15
  77. data/lib/generators/ahoy/stores/templates/active_record_event_model.rb +0 -12
  78. data/lib/generators/ahoy/stores/templates/active_record_events_migration.rb +0 -19
  79. data/lib/generators/ahoy/stores/templates/active_record_initializer.rb +0 -3
  80. data/lib/generators/ahoy/stores/templates/active_record_visit_model.rb +0 -4
  81. data/lib/generators/ahoy/stores/templates/active_record_visits_migration.rb +0 -57
  82. data/lib/generators/ahoy/stores/templates/bunny_initializer.rb +0 -9
  83. data/lib/generators/ahoy/stores/templates/custom_initializer.rb +0 -10
  84. data/lib/generators/ahoy/stores/templates/fluentd_initializer.rb +0 -3
  85. data/lib/generators/ahoy/stores/templates/kafka_initializer.rb +0 -9
  86. data/lib/generators/ahoy/stores/templates/kinesis_firehose_initializer.rb +0 -17
  87. data/lib/generators/ahoy/stores/templates/log_initializer.rb +0 -3
  88. data/lib/generators/ahoy/stores/templates/mongoid_initializer.rb +0 -3
  89. data/lib/generators/ahoy/stores/templates/nats_initializer.rb +0 -9
  90. data/lib/generators/ahoy/stores/templates/nsq_initializer.rb +0 -9
  91. data/test/properties/mysql_json_test.rb +0 -18
  92. data/test/properties/mysql_text_test.rb +0 -19
  93. data/test/properties/postgresql_hstore_test.rb +0 -18
  94. data/test/properties/postgresql_json_test.rb +0 -18
  95. data/test/properties/postgresql_jsonb_test.rb +0 -18
  96. data/test/properties/postgresql_text_test.rb +0 -19
  97. data/test/test_helper.rb +0 -99
  98. data/test/visit_properties_test.rb +0 -44
data/lib/ahoy/tracker.rb CHANGED
@@ -1,46 +1,60 @@
1
+ require "active_support/core_ext/digest/uuid"
2
+
1
3
  module Ahoy
2
4
  class Tracker
5
+ UUID_NAMESPACE = "a82ae811-5011-45ab-a728-569df7499c5f"
6
+
3
7
  attr_reader :request, :controller
4
8
 
5
- def initialize(options = {})
9
+ def initialize(**options)
6
10
  @store = Ahoy::Store.new(options.merge(ahoy: self))
7
11
  @controller = options[:controller]
8
12
  @request = options[:request] || @controller.try(:request)
13
+ @visit_token = options[:visit_token]
14
+ @user = options[:user]
9
15
  @options = options
10
16
  end
11
17
 
18
+ # can't use keyword arguments here
12
19
  def track(name, properties = {}, options = {})
13
20
  if exclude?
14
21
  debug "Event excluded"
15
- elsif missing_params?
16
- debug "Missing required parameters"
17
22
  else
18
- options = options.dup
19
-
20
- options[:time] = trusted_time(options[:time])
21
- options[:id] = ensure_uuid(options[:id] || generate_id)
22
-
23
- @store.track_event(name, properties, options)
23
+ data = {
24
+ visit_token: visit_token,
25
+ user_id: user.try(:id),
26
+ name: name.to_s,
27
+ properties: properties,
28
+ time: trusted_time(options[:time]),
29
+ event_id: options[:id] || generate_id
30
+ }.select { |_, v| v }
31
+
32
+ @store.track_event(data)
24
33
  end
25
34
  true
26
35
  rescue => e
27
36
  report_exception(e)
28
37
  end
29
38
 
30
- def track_visit(options = {})
39
+ def track_visit(defer: false, started_at: nil)
31
40
  if exclude?
32
41
  debug "Visit excluded"
33
- elsif missing_params?
34
- debug "Missing required parameters"
35
42
  else
36
- if options[:defer]
43
+ if defer
37
44
  set_cookie("ahoy_track", true, nil, false)
38
45
  else
39
- options = options.dup
46
+ delete_cookie("ahoy_track")
40
47
 
41
- options[:started_at] ||= Time.zone.now
48
+ data = {
49
+ visit_token: visit_token,
50
+ visitor_token: visitor_token,
51
+ user_id: user.try(:id),
52
+ started_at: trusted_time(started_at),
53
+ }.merge(visit_properties).select { |_, v| v }
42
54
 
43
- @store.track_visit(options)
55
+ @store.track_visit(data)
56
+
57
+ Ahoy::GeocodeV2Job.perform_later(visit_token, data[:ip]) if Ahoy.geocode && data[:ip]
44
58
  end
45
59
  end
46
60
  true
@@ -48,11 +62,28 @@ module Ahoy
48
62
  report_exception(e)
49
63
  end
50
64
 
65
+ def geocode(data)
66
+ data = {
67
+ visit_token: visit_token
68
+ }.merge(data).select { |_, v| v }
69
+
70
+ @store.geocode(data)
71
+ true
72
+ rescue => e
73
+ report_exception(e)
74
+ end
75
+
51
76
  def authenticate(user)
52
77
  if exclude?
53
78
  debug "Authentication excluded"
54
79
  else
55
- @store.authenticate(user)
80
+ @store.user = user
81
+
82
+ data = {
83
+ visit_token: visit_token,
84
+ user_id: user.try(:id)
85
+ }
86
+ @store.authenticate(data)
56
87
  end
57
88
  true
58
89
  rescue => e
@@ -63,16 +94,12 @@ module Ahoy
63
94
  @visit ||= @store.visit
64
95
  end
65
96
 
66
- def visit_id
67
- @visit_id ||= ensure_uuid(visit_token_helper)
68
- end
69
-
70
- def visitor_id
71
- @visitor_id ||= ensure_uuid(visitor_token_helper)
97
+ def visit_or_create
98
+ @visit ||= @store.visit_or_create
72
99
  end
73
100
 
74
101
  def new_visit?
75
- !existing_visit_token
102
+ Ahoy.cookies ? !existing_visit_token : visit.nil?
76
103
  end
77
104
 
78
105
  def new_visitor?
@@ -80,12 +107,12 @@ module Ahoy
80
107
  end
81
108
 
82
109
  def set_visit_cookie
83
- set_cookie("ahoy_visit", visit_id, Ahoy.visit_duration)
110
+ set_cookie("ahoy_visit", visit_token, Ahoy.visit_duration)
84
111
  end
85
112
 
86
113
  def set_visitor_cookie
87
114
  if new_visitor?
88
- set_cookie("ahoy_visitor", visitor_id, Ahoy.visitor_duration)
115
+ set_cookie("ahoy_visitor", visitor_token, Ahoy.visitor_duration)
89
116
  end
90
117
  end
91
118
 
@@ -93,18 +120,30 @@ module Ahoy
93
120
  @user ||= @store.user
94
121
  end
95
122
 
96
- # TODO better name
97
123
  def visit_properties
98
- @visit_properties ||= Ahoy::VisitProperties.new(request, api: api?)
124
+ @visit_properties ||= request ? Ahoy::VisitProperties.new(request, api: api?).generate : {}
99
125
  end
100
126
 
101
127
  def visit_token
102
128
  @visit_token ||= ensure_token(visit_token_helper)
103
129
  end
130
+ alias_method :visit_id, :visit_token
104
131
 
105
132
  def visitor_token
106
133
  @visitor_token ||= ensure_token(visitor_token_helper)
107
134
  end
135
+ alias_method :visitor_id, :visitor_token
136
+
137
+ def reset
138
+ reset_visit
139
+ delete_cookie("ahoy_visitor")
140
+ end
141
+
142
+ def reset_visit
143
+ delete_cookie("ahoy_visit")
144
+ delete_cookie("ahoy_events")
145
+ delete_cookie("ahoy_track")
146
+ end
108
147
 
109
148
  protected
110
149
 
@@ -112,8 +151,9 @@ module Ahoy
112
151
  @options[:api]
113
152
  end
114
153
 
154
+ # private, but used by API
115
155
  def missing_params?
116
- if api? && Ahoy.protect_from_forgery
156
+ if Ahoy.cookies && api? && Ahoy.protect_from_forgery
117
157
  !(existing_visit_token && existing_visitor_token)
118
158
  else
119
159
  false
@@ -121,35 +161,42 @@ module Ahoy
121
161
  end
122
162
 
123
163
  def set_cookie(name, value, duration = nil, use_domain = true)
124
- cookie = {
125
- value: value
126
- }
164
+ # safety net
165
+ return unless Ahoy.cookies && request
166
+
167
+ cookie = Ahoy.cookie_options.merge(value: value)
127
168
  cookie[:expires] = duration.from_now if duration
128
- domain = Ahoy.cookie_domain || Ahoy.domain
129
- cookie[:domain] = domain if domain && use_domain
169
+ # prefer cookie_options[:domain] over cookie_domain
170
+ cookie[:domain] ||= Ahoy.cookie_domain if Ahoy.cookie_domain
171
+ cookie.delete(:domain) unless use_domain
130
172
  request.cookie_jar[name] = cookie
131
173
  end
132
174
 
133
- def trusted_time(time)
175
+ def delete_cookie(name)
176
+ request.cookie_jar.delete(name) if request && request.cookie_jar[name]
177
+ end
178
+
179
+ def trusted_time(time = nil)
134
180
  if !time || (api? && !(1.minute.ago..Time.now).cover?(time))
135
- Time.zone.now
181
+ Time.current
136
182
  else
137
183
  time
138
184
  end
139
185
  end
140
186
 
141
187
  def exclude?
142
- @store.exclude?
188
+ unless defined?(@exclude)
189
+ @exclude = @store.exclude?
190
+ end
191
+ @exclude
143
192
  end
144
193
 
145
- # odd pattern for backwards compatibility
146
- # TODO remove this method in next major release
147
194
  def report_exception(e)
148
- Safely.safely do
149
- @store.report_exception(e)
150
- if Rails.env.development? || Rails.env.test?
151
- raise e
152
- end
195
+ if defined?(ActionDispatch::RemoteIp::IpSpoofAttackError) && e.is_a?(ActionDispatch::RemoteIp::IpSpoofAttackError)
196
+ debug "Tracking excluded due to IP spoofing"
197
+ else
198
+ raise e if !defined?(Rails) || Rails.env.development? || Rails.env.test?
199
+ Safely.report_exception(e)
153
200
  end
154
201
  end
155
202
 
@@ -160,6 +207,7 @@ module Ahoy
160
207
  def visit_token_helper
161
208
  @visit_token_helper ||= begin
162
209
  token = existing_visit_token
210
+ token ||= visit_anonymity_set unless Ahoy.cookies
163
211
  token ||= generate_id unless Ahoy.api_only
164
212
  token
165
213
  end
@@ -168,6 +216,7 @@ module Ahoy
168
216
  def visitor_token_helper
169
217
  @visitor_token_helper ||= begin
170
218
  token = existing_visitor_token
219
+ token ||= visitor_anonymity_set unless Ahoy.cookies
171
220
  token ||= generate_id unless Ahoy.api_only
172
221
  token
173
222
  end
@@ -176,7 +225,7 @@ module Ahoy
176
225
  def existing_visit_token
177
226
  @existing_visit_token ||= begin
178
227
  token = visit_header
179
- token ||= visit_cookie unless api? && Ahoy.protect_from_forgery
228
+ token ||= visit_cookie if Ahoy.cookies && !(api? && Ahoy.protect_from_forgery)
180
229
  token ||= visit_param if api?
181
230
  token
182
231
  end
@@ -185,12 +234,20 @@ module Ahoy
185
234
  def existing_visitor_token
186
235
  @existing_visitor_token ||= begin
187
236
  token = visitor_header
188
- token ||= visitor_cookie unless api? && Ahoy.protect_from_forgery
237
+ token ||= visitor_cookie if Ahoy.cookies && !(api? && Ahoy.protect_from_forgery)
189
238
  token ||= visitor_param if api?
190
239
  token
191
240
  end
192
241
  end
193
242
 
243
+ def visit_anonymity_set
244
+ @visit_anonymity_set ||= Digest::UUID.uuid_v5(UUID_NAMESPACE, ["visit", Ahoy.mask_ip(request.remote_ip), request.user_agent].join("/"))
245
+ end
246
+
247
+ def visitor_anonymity_set
248
+ @visitor_anonymity_set ||= Digest::UUID.uuid_v5(UUID_NAMESPACE, ["visitor", Ahoy.mask_ip(request.remote_ip), request.user_agent].join("/"))
249
+ end
250
+
194
251
  def visit_cookie
195
252
  @visit_cookie ||= request && request.cookies["ahoy_visit"]
196
253
  end
@@ -215,16 +272,13 @@ module Ahoy
215
272
  @visitor_param ||= request && request.params["visitor_token"]
216
273
  end
217
274
 
218
- def ensure_uuid(id)
219
- Ahoy.ensure_uuid(id) if id
220
- end
221
-
222
275
  def ensure_token(token)
276
+ token = Ahoy::Utils.ensure_utf8(token)
223
277
  token.to_s.gsub(/[^a-z0-9\-]/i, "").first(64) if token
224
278
  end
225
279
 
226
280
  def debug(message)
227
- Rails.logger.debug { "[ahoy] #{message}" }
281
+ Ahoy.log message
228
282
  end
229
283
  end
230
284
  end
data/lib/ahoy/utils.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Ahoy
2
+ module Utils
3
+ def self.ensure_utf8(str)
4
+ str.encode("UTF-8", "binary", invalid: :replace, undef: :replace, replace: "") if str
5
+ end
6
+ end
7
+ end
data/lib/ahoy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "1.5.5"
2
+ VERSION = "4.2.1"
3
3
  end
@@ -1,60 +1,122 @@
1
+ require "cgi"
2
+ require "device_detector"
3
+ require "uri"
4
+
1
5
  module Ahoy
2
6
  class VisitProperties
3
- REQUEST_KEYS = [:ip, :user_agent, :referrer, :landing_page, :platform, :app_version, :os_version, :screen_height, :screen_width]
4
- TRAFFIC_SOURCE_KEYS = [:referring_domain, :search_keyword]
5
- UTM_PARAMETER_KEYS = [:utm_source, :utm_medium, :utm_term, :utm_content, :utm_campaign]
6
- TECHNOLOGY_KEYS = [:browser, :os, :device_type]
7
- LOCATION_KEYS = [:country, :region, :city, :postal_code, :latitude, :longitude]
8
-
9
- KEYS = REQUEST_KEYS + TRAFFIC_SOURCE_KEYS + UTM_PARAMETER_KEYS + TECHNOLOGY_KEYS + LOCATION_KEYS
7
+ attr_reader :request, :params, :referrer, :landing_page
10
8
 
11
- delegate(*REQUEST_KEYS, to: :request_deckhand)
12
- delegate(*TRAFFIC_SOURCE_KEYS, to: :traffic_source_deckhand)
13
- delegate(*(UTM_PARAMETER_KEYS + [:landing_params]), to: :utm_parameter_deckhand)
14
- delegate(*TECHNOLOGY_KEYS, to: :technology_deckhand)
15
- delegate(*LOCATION_KEYS, to: :location_deckhand)
16
-
17
- def initialize(request, options = {})
9
+ def initialize(request, api:)
18
10
  @request = request
19
- @options = options
11
+ @params = request.params
12
+ @referrer = api ? params["referrer"] : request.referer
13
+ @landing_page = api ? params["landing_page"] : request.original_url
20
14
  end
21
15
 
22
- def [](key)
23
- send(key)
16
+ def generate
17
+ @generate ||= request_properties.merge(tech_properties).merge(traffic_properties).merge(utm_properties)
24
18
  end
25
19
 
26
- def keys
27
- if Ahoy.geocode == true # no location keys for :async
28
- KEYS
29
- else
30
- KEYS - LOCATION_KEYS
20
+ private
21
+
22
+ def utm_properties
23
+ landing_params = {}
24
+ begin
25
+ landing_uri = URI.parse(landing_page)
26
+ # could also use Rack::Utils.parse_nested_query
27
+ landing_params = CGI.parse(landing_uri.query) if landing_uri
28
+ rescue
29
+ # do nothing
30
+ end
31
+
32
+ props = {}
33
+ %w(utm_source utm_medium utm_term utm_content utm_campaign).each do |name|
34
+ props[name.to_sym] = params[name] || landing_params[name].try(:first)
31
35
  end
36
+ props
32
37
  end
33
38
 
34
- def to_hash
35
- keys.inject({}) { |memo, key| memo[key] = send(key); memo }
39
+ def traffic_properties
40
+ uri = URI.parse(referrer) rescue nil
41
+ {
42
+ referring_domain: uri.try(:host).try(:first, 255)
43
+ }
36
44
  end
37
45
 
38
- protected
46
+ def tech_properties
47
+ if Ahoy.user_agent_parser == :device_detector
48
+ client = DeviceDetector.new(request.user_agent)
49
+ device_type =
50
+ case client.device_type
51
+ when "smartphone"
52
+ "Mobile"
53
+ when "tv"
54
+ "TV"
55
+ else
56
+ client.device_type.try(:titleize)
57
+ end
39
58
 
40
- def request_deckhand
41
- @request_deckhand ||= Deckhands::RequestDeckhand.new(@request, @options)
42
- end
59
+ {
60
+ browser: client.name,
61
+ os: client.os_name,
62
+ device_type: device_type
63
+ }
64
+ else
65
+ raise "Add browser to your Gemfile to use legacy user agent parsing" unless defined?(Browser)
66
+ raise "Add user_agent_parser to your Gemfile to use legacy user agent parsing" unless defined?(UserAgentParser)
43
67
 
44
- def traffic_source_deckhand
45
- @traffic_source_deckhand ||= Deckhands::TrafficSourceDeckhand.new(request_deckhand.referrer)
46
- end
68
+ # cache for performance
69
+ @@user_agent_parser ||= UserAgentParser::Parser.new
70
+
71
+ user_agent = request.user_agent
72
+ agent = @@user_agent_parser.parse(user_agent)
73
+ browser = Browser.new(user_agent)
74
+ device_type =
75
+ if browser.bot?
76
+ "Bot"
77
+ elsif browser.device.tv?
78
+ "TV"
79
+ elsif browser.device.console?
80
+ "Console"
81
+ elsif browser.device.tablet?
82
+ "Tablet"
83
+ elsif browser.device.mobile?
84
+ "Mobile"
85
+ else
86
+ "Desktop"
87
+ end
47
88
 
48
- def utm_parameter_deckhand
49
- @utm_parameter_deckhand ||= Deckhands::UtmParameterDeckhand.new(request_deckhand.landing_page, request_deckhand.params)
89
+ {
90
+ browser: agent.name,
91
+ os: agent.os.name,
92
+ device_type: device_type
93
+ }
94
+ end
50
95
  end
51
96
 
52
- def technology_deckhand
53
- @technology_deckhand ||= Deckhands::TechnologyDeckhand.new(request_deckhand.user_agent)
97
+ # masking based on Google Analytics anonymization
98
+ # https://support.google.com/analytics/answer/2763052
99
+ def ip
100
+ ip = request.remote_ip
101
+ if ip && Ahoy.mask_ips
102
+ Ahoy.mask_ip(ip)
103
+ else
104
+ ip
105
+ end
54
106
  end
55
107
 
56
- def location_deckhand
57
- @location_deckhand ||= Deckhands::LocationDeckhand.new(request_deckhand.ip)
108
+ def request_properties
109
+ {
110
+ ip: ip,
111
+ user_agent: Ahoy::Utils.ensure_utf8(request.user_agent),
112
+ referrer: referrer,
113
+ landing_page: landing_page,
114
+ platform: params["platform"],
115
+ app_version: params["app_version"],
116
+ os_version: params["os_version"],
117
+ screen_height: params["screen_height"],
118
+ screen_width: params["screen_width"]
119
+ }
58
120
  end
59
121
  end
60
122
  end