ahoy_matey 3.0.5 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,64 +8,40 @@ module Ahoy
8
8
  end
9
9
 
10
10
  def where_props(properties)
11
- relation = self
12
- if respond_to?(:columns_hash)
13
- column_type = columns_hash["properties"].type
14
- adapter_name = connection.adapter_name.downcase
15
- else
16
- adapter_name = "mongoid"
17
- end
11
+ return all if properties.empty?
12
+
13
+ adapter_name = respond_to?(:connection) ? connection.adapter_name.downcase : "mongoid"
18
14
  case adapter_name
19
15
  when "mongoid"
20
- relation = where(Hash[properties.map { |k, v| ["properties.#{k}", v] }])
16
+ where(properties.to_h { |k, v| ["properties.#{k}", v] })
21
17
  when /mysql/
22
- if column_type == :json
23
- properties.each do |k, v|
18
+ where("JSON_CONTAINS(properties, ?, '$') = 1", properties.to_json)
19
+ when /postgres|postgis/
20
+ case columns_hash["properties"].type
21
+ when :hstore
22
+ properties.inject(all) do |relation, (k, v)|
24
23
  if v.nil?
25
- v = "null"
26
- elsif v == true
27
- v = "true"
24
+ relation.where("properties -> ? IS NULL", k.to_s)
25
+ else
26
+ relation.where("properties -> ? = ?", k.to_s, v.to_s)
28
27
  end
29
-
30
- relation = relation.where("JSON_UNQUOTE(properties -> ?) = ?", "$.#{k}", v.as_json)
31
28
  end
29
+ when :jsonb
30
+ where("properties @> ?", properties.to_json)
32
31
  else
33
- properties.each do |k, v|
34
- # TODO cast to json instead
35
- relation = relation.where("properties REGEXP ?", "[{,]#{{k.to_s => v}.to_json.sub(/\A\{/, "").sub(/\}\z/, "").gsub("+", "\\\\+")}[,}]")
36
- end
32
+ where("properties::jsonb @> ?", properties.to_json)
37
33
  end
38
- when /postgres|postgis/
39
- if column_type == :jsonb
40
- relation = relation.where("properties @> ?", properties.to_json)
41
- elsif column_type == :json
42
- properties.each do |k, v|
43
- relation =
44
- if v.nil?
45
- relation.where("properties ->> ? IS NULL", k.to_s)
46
- else
47
- relation.where("properties ->> ? = ?", k.to_s, v.as_json.to_s)
48
- end
49
- end
50
- elsif column_type == :hstore
51
- properties.each do |k, v|
52
- relation =
53
- if v.nil?
54
- relation.where("properties -> ? IS NULL", k.to_s)
55
- else
56
- relation.where("properties -> ? = ?", k.to_s, v.to_s)
57
- end
58
- end
59
- else
60
- properties.each do |k, v|
61
- # TODO cast to jsonb instead
62
- relation = relation.where("properties SIMILAR TO ?", "%[{,]#{{k.to_s => v}.to_json.sub(/\A\{/, "").sub(/\}\z/, "").gsub("+", "\\\\+")}[,}]%")
34
+ when /sqlite/
35
+ properties.inject(all) do |relation, (k, v)|
36
+ if v.nil?
37
+ relation.where("JSON_EXTRACT(properties, ?) IS NULL", "$.#{k}")
38
+ else
39
+ relation.where("JSON_EXTRACT(properties, ?) = ?", "$.#{k}", v.as_json)
63
40
  end
64
41
  end
65
42
  else
66
43
  raise "Adapter not supported: #{adapter_name}"
67
44
  end
68
- relation
69
45
  end
70
46
  alias_method :where_properties, :where_props
71
47
 
@@ -73,39 +49,32 @@ module Ahoy
73
49
  # like with group
74
50
  props.flatten!
75
51
 
76
- relation = self
77
- if respond_to?(:columns_hash)
78
- column_type = columns_hash["properties"].type
79
- adapter_name = connection.adapter_name.downcase
80
- else
81
- adapter_name = "mongoid"
82
- end
52
+ relation = all
53
+ adapter_name = respond_to?(:connection) ? connection.adapter_name.downcase : "mongoid"
83
54
  case adapter_name
84
55
  when "mongoid"
85
56
  raise "Adapter not supported: #{adapter_name}"
86
57
  when /mysql/
87
- if connection.try(:mariadb?)
88
- props.each do |prop|
89
- quoted_prop = connection.quote("$.#{prop}")
90
- relation = relation.group("JSON_UNQUOTE(JSON_EXTRACT(properties, #{quoted_prop}))")
91
- end
92
- else
93
- column = column_type == :json ? "properties" : "CAST(properties AS JSON)"
94
- props.each do |prop|
95
- quoted_prop = connection.quote("$.#{prop}")
96
- relation = relation.group("JSON_UNQUOTE(JSON_EXTRACT(#{column}, #{quoted_prop}))")
97
- end
58
+ props.each do |prop|
59
+ quoted_prop = connection.quote("$.#{prop}")
60
+ relation = relation.group("JSON_UNQUOTE(JSON_EXTRACT(properties, #{quoted_prop}))")
98
61
  end
99
62
  when /postgres|postgis/
100
63
  # convert to jsonb to fix
101
64
  # could not identify an equality operator for type json
102
65
  # and for text columns
66
+ column_type = columns_hash["properties"].type
103
67
  cast = [:jsonb, :hstore].include?(column_type) ? "" : "::jsonb"
104
68
 
105
69
  props.each do |prop|
106
70
  quoted_prop = connection.quote(prop)
107
71
  relation = relation.group("properties#{cast} -> #{quoted_prop}")
108
72
  end
73
+ when /sqlite/
74
+ props.each do |prop|
75
+ quoted_prop = connection.quote("$.#{prop}")
76
+ relation = relation.group("JSON_EXTRACT(properties, #{quoted_prop})")
77
+ end
109
78
  else
110
79
  raise "Adapter not supported: #{adapter_name}"
111
80
  end
data/lib/ahoy/tracker.rb CHANGED
@@ -19,8 +19,6 @@ module Ahoy
19
19
  def track(name, properties = {}, options = {})
20
20
  if exclude?
21
21
  debug "Event excluded"
22
- elsif missing_params?
23
- debug "Missing required parameters"
24
22
  else
25
23
  data = {
26
24
  visit_token: visit_token,
@@ -41,8 +39,6 @@ module Ahoy
41
39
  def track_visit(defer: false, started_at: nil)
42
40
  if exclude?
43
41
  debug "Visit excluded"
44
- elsif missing_params?
45
- debug "Missing required parameters"
46
42
  else
47
43
  if defer
48
44
  set_cookie("ahoy_track", true, nil, false)
@@ -67,16 +63,12 @@ module Ahoy
67
63
  end
68
64
 
69
65
  def geocode(data)
70
- if exclude?
71
- debug "Geocode excluded"
72
- else
73
- data = {
74
- visit_token: visit_token
75
- }.merge(data).select { |_, v| v }
66
+ data = {
67
+ visit_token: visit_token
68
+ }.merge(data).select { |_, v| v }
76
69
 
77
- @store.geocode(data)
78
- true
79
- end
70
+ @store.geocode(data)
71
+ true
80
72
  rescue => e
81
73
  report_exception(e)
82
74
  end
@@ -159,6 +151,7 @@ module Ahoy
159
151
  @options[:api]
160
152
  end
161
153
 
154
+ # private, but used by API
162
155
  def missing_params?
163
156
  if Ahoy.cookies && api? && Ahoy.protect_from_forgery
164
157
  !(existing_visit_token && existing_visitor_token)
@@ -192,7 +185,10 @@ module Ahoy
192
185
  end
193
186
 
194
187
  def exclude?
195
- @store.exclude?
188
+ unless defined?(@exclude)
189
+ @exclude = @store.exclude?
190
+ end
191
+ @exclude
196
192
  end
197
193
 
198
194
  def report_exception(e)
data/lib/ahoy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "3.0.5"
2
+ VERSION = "4.2.1"
3
3
  end
data/lib/ahoy.rb CHANGED
@@ -1,24 +1,24 @@
1
+ # stdlib
1
2
  require "ipaddr"
2
3
 
3
4
  # dependencies
4
5
  require "active_support"
5
6
  require "active_support/core_ext"
6
- require "geocoder"
7
7
  require "safely/core"
8
8
 
9
9
  # modules
10
- require "ahoy/utils"
11
- require "ahoy/base_store"
12
- require "ahoy/controller"
13
- require "ahoy/database_store"
14
- require "ahoy/helper"
15
- require "ahoy/model"
16
- require "ahoy/query_methods"
17
- require "ahoy/tracker"
18
- require "ahoy/version"
19
- require "ahoy/visit_properties"
20
-
21
- require "ahoy/engine" if defined?(Rails)
10
+ require_relative "ahoy/utils"
11
+ require_relative "ahoy/base_store"
12
+ require_relative "ahoy/controller"
13
+ require_relative "ahoy/database_store"
14
+ require_relative "ahoy/helper"
15
+ require_relative "ahoy/model"
16
+ require_relative "ahoy/query_methods"
17
+ require_relative "ahoy/tracker"
18
+ require_relative "ahoy/version"
19
+ require_relative "ahoy/visit_properties"
20
+
21
+ require_relative "ahoy/engine" if defined?(Rails)
22
22
 
23
23
  module Ahoy
24
24
  mattr_accessor :visit_duration
@@ -43,7 +43,7 @@ module Ahoy
43
43
  self.quiet = true
44
44
 
45
45
  mattr_accessor :geocode
46
- self.geocode = true
46
+ self.geocode = false
47
47
 
48
48
  mattr_accessor :max_content_length
49
49
  self.max_content_length = 8192
@@ -104,6 +104,14 @@ module Ahoy
104
104
  addr.mask(48).to_s
105
105
  end
106
106
  end
107
+
108
+ def self.instance
109
+ Thread.current[:ahoy]
110
+ end
111
+
112
+ def self.instance=(value)
113
+ Thread.current[:ahoy] = value
114
+ end
107
115
  end
108
116
 
109
117
  ActiveSupport.on_load(:action_controller) do
@@ -118,11 +126,6 @@ ActiveSupport.on_load(:action_view) do
118
126
  include Ahoy::Helper
119
127
  end
120
128
 
121
- # Mongoid
122
- # TODO use
123
- # ActiveSupport.on_load(:mongoid) do
124
- # Mongoid::Document::ClassMethods.include(Ahoy::Model)
125
- # end
126
- if defined?(ActiveModel)
127
- ActiveModel::Callbacks.include(Ahoy::Model)
129
+ ActiveSupport.on_load(:mongoid) do
130
+ Mongoid::Document::ClassMethods.include(Ahoy::Model)
128
131
  end
data/lib/ahoy_matey.rb CHANGED
@@ -1 +1 @@
1
- require "ahoy"
1
+ require_relative "ahoy"
@@ -1,3 +1,4 @@
1
+ require "rails/generators"
1
2
  require "rails/generators/active_record"
2
3
 
3
4
  module Ahoy
@@ -17,9 +18,7 @@ module Ahoy
17
18
  end
18
19
 
19
20
  def properties_type
20
- # use connection_config instead of connection.adapter
21
- # so database connection isn't needed
22
- case ActiveRecord::Base.connection_config[:adapter].to_s
21
+ case adapter
23
22
  when /postg/i # postgres, postgis
24
23
  "jsonb"
25
24
  when /mysql/i
@@ -29,13 +28,40 @@ module Ahoy
29
28
  end
30
29
  end
31
30
 
31
+ # requires database connection to check for MariaDB
32
+ def serialize_properties?
33
+ properties_type == "text" || (properties_type == "json" && ActiveRecord::Base.connection.try(:mariadb?))
34
+ end
35
+
36
+ # use connection_config instead of connection.adapter
37
+ # so database connection isn't needed
38
+ def adapter
39
+ if ActiveRecord::VERSION::STRING.to_f >= 6.1
40
+ ActiveRecord::Base.connection_db_config.adapter.to_s
41
+ else
42
+ ActiveRecord::Base.connection_config[:adapter].to_s
43
+ end
44
+ end
45
+
32
46
  def rails52?
33
- ActiveRecord::VERSION::STRING >= "5.2"
47
+ ActiveRecord::VERSION::STRING.to_f >= 5.2
34
48
  end
35
49
 
36
50
  def migration_version
37
51
  "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
38
52
  end
53
+
54
+ def primary_key_type
55
+ ", id: :#{key_type}" if key_type
56
+ end
57
+
58
+ def foreign_key_type
59
+ ", type: :#{key_type}" if key_type
60
+ end
61
+
62
+ def key_type
63
+ Rails.configuration.generators.options.dig(:active_record, :primary_key_type)
64
+ end
39
65
  end
40
66
  end
41
67
  end
@@ -4,7 +4,7 @@ class Ahoy::Event < ApplicationRecord
4
4
  self.table_name = "ahoy_events"
5
5
 
6
6
  belongs_to :visit
7
- belongs_to :user, optional: true<% if properties_type == "text" %>
7
+ belongs_to :user, optional: true<% if serialize_properties? %>
8
8
 
9
9
  serialize :properties, JSON<% end %>
10
10
  end
@@ -1,6 +1,6 @@
1
1
  class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
- create_table :ahoy_visits do |t|
3
+ create_table :ahoy_visits<%= primary_key_type %> do |t|
4
4
  t.string :visit_token
5
5
  t.string :visitor_token
6
6
 
@@ -8,7 +8,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
8
8
  # simply remove any you don't want
9
9
 
10
10
  # user
11
- t.references :user
11
+ t.references :user<%= foreign_key_type %>
12
12
 
13
13
  # standard
14
14
  t.string :ip
@@ -46,9 +46,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
46
46
 
47
47
  add_index :ahoy_visits, :visit_token, unique: true
48
48
 
49
- create_table :ahoy_events do |t|
50
- t.references :visit
51
- t.references :user
49
+ create_table :ahoy_events<%= primary_key_type %> do |t|
50
+ t.references :visit<%= foreign_key_type %>
51
+ t.references :user<%= foreign_key_type %>
52
52
 
53
53
  t.string :name
54
54
  t.<%= properties_type %> :properties
@@ -18,3 +18,8 @@ end
18
18
 
19
19
  # set to true for JavaScript tracking
20
20
  Ahoy.api = false
21
+
22
+ # set to true for geocoding (and add the geocoder gem to your Gemfile)
23
+ # we recommend configuring local geocoding as well
24
+ # see https://github.com/ankane/ahoy#geocoding
25
+ Ahoy.geocode = false
@@ -3,3 +3,8 @@ end
3
3
 
4
4
  # set to true for JavaScript tracking
5
5
  Ahoy.api = false
6
+
7
+ # set to true for geocoding (and add the geocoder gem to your Gemfile)
8
+ # we recommend configuring local geocoding as well
9
+ # see https://github.com/ankane/ahoy#geocoding
10
+ Ahoy.geocode = false
@@ -2,7 +2,7 @@ class Ahoy::Event
2
2
  include Mongoid::Document
3
3
 
4
4
  # associations
5
- belongs_to :visit, index: true
5
+ belongs_to :visit, class_name: "Ahoy::Visit", index: true
6
6
  belongs_to :user, index: true, optional: true
7
7
 
8
8
  # fields