searchjoy 1.0.0 → 1.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 807861a09661dcbcf5a2f4c580e189e3df4d7f67e3a1dbb863408ce7fc1091c3
4
- data.tar.gz: b901df59229c2a6daa3781a44b66b89d87d171aeede2acbd17f9ef135e78c7fd
3
+ metadata.gz: c6e0ac0fd71243df3a3395c6ab793fe20d523ed435634b3adf73c44ac58aa167
4
+ data.tar.gz: 83708806572742373d3531750d867bdf9c4338df15546f4361e8d0b927330099
5
5
  SHA512:
6
- metadata.gz: 4c7d96778f812145a132f8f756ac2ca1bb88429758db180402f47b0f56d68b9dfe63e461668b28a51162018f7f97f49c6f94100e3430a79bf54056cd2b4fcdbb
7
- data.tar.gz: 744e8fff8679dfc197d4439c7cda43cc21b23f38e12aec883a1b095481ae4f3db597b3f26bc2c409c51c07928a4f68a4a5114b387905b5c0c6f119611dbac7b1
6
+ metadata.gz: 94f1c69497cb80375308e6694c7b43731f75baf93073c26baf16b446fb65fc6b335d252882f42e1391dd0f242b1a7b7e42587e3908cbf6db36a603fdf78a4477
7
+ data.tar.gz: b1eb7619d49602c90ca34dcae225c89d095c4357ee57970f61ac73d5b4ba336feccabb28eb4db2a9974215fe5c8d988441b2390e43bfac7936dd54ef91433869
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 1.2.0 (2024-06-24)
2
+
3
+ - Dropped support for Ruby < 3.1 and Rails < 6.1
4
+
5
+ ## 1.1.0 (2023-02-07)
6
+
7
+ - Improved dashboard labels
8
+ - Improved CSP support
9
+ - Dropped support for Ruby < 2.7 and Rails < 6
10
+
1
11
  ## 1.0.0 (2022-05-10)
2
12
 
3
13
  - Added support for multiple conversions per search
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013-2022 Andrew Kane
1
+ Copyright (c) 2013-2024 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -7,14 +7,14 @@ Search analytics made easy
7
7
  [![Screenshot](https://searchjoy.dokkuapp.com/assets/searchjoy-7be12d922ca8b31b7d7440e618b0c666698a4b15752653a0c5c45e3dd2737142.png)](https://searchjoy.dokkuapp.com/)
8
8
 
9
9
  - view searches in real-time
10
- - track conversions week over week
10
+ - track conversion rate week over week
11
11
  - monitor the performance of top searches
12
12
 
13
- Works with any search platform, including Elasticsearch, Sphinx, and Solr
13
+ Works with any search platform, including Elasticsearch, OpenSearch, Sphinx, and Solr
14
14
 
15
15
  :cupid: An amazing companion to [Searchkick](https://github.com/ankane/searchkick)
16
16
 
17
- [![Build Status](https://github.com/ankane/searchjoy/workflows/build/badge.svg?branch=master)](https://github.com/ankane/searchjoy/actions)
17
+ [![Build Status](https://github.com/ankane/searchjoy/actions/workflows/build.yml/badge.svg)](https://github.com/ankane/searchjoy/actions)
18
18
 
19
19
  ## Installation
20
20
 
@@ -122,7 +122,11 @@ ENV["SEARCHJOY_PASSWORD"] = "secret"
122
122
  Data should only be retained for as long as it’s needed. Delete older data with:
123
123
 
124
124
  ```ruby
125
- Searchjoy::Search.where("created_at < ?", 1.year.ago).in_batches.delete_all
125
+ Searchjoy::Search.where("created_at < ?", 1.year.ago).find_in_batches do |searches|
126
+ search_ids = searches.map(&:id)
127
+ Searchjoy::Conversion.where(search_id: search_ids).delete_all
128
+ Searchjoy::Search.where(id: search_ids).delete_all
129
+ end
126
130
  ```
127
131
 
128
132
  You can use [Rollup](https://github.com/ankane/rollup) to aggregate important data before you do.
@@ -134,7 +138,10 @@ Searchjoy::Search.rollup("Searches")
134
138
  Delete data for a specific user with:
135
139
 
136
140
  ```ruby
137
- Searchjoy::Search.where(user_id: 1).delete_all
141
+ user_id = 123
142
+ search_ids = Searchjoy::Search.where(user_id: user_id).pluck(:id)
143
+ Searchjoy::Conversion.where(search_id: search_ids).delete_all
144
+ Searchjoy::Search.where(id: search_ids).delete_all
138
145
  ```
139
146
 
140
147
  ## Customize
@@ -34,12 +34,12 @@ module Searchjoy
34
34
 
35
35
  relation = Searchjoy::Search.where(search_type: params[:search_type])
36
36
  @searches_by_week = relation.group_by_period(period, :created_at, time_zone: @time_zone, range: @time_range).count
37
- @conversions_by_week = relation.where.not(converted_at: nil).group_by_period(period, :created_at, time_zone: @time_zone, range: @time_range).count
37
+ @converted_by_week = relation.where.not(converted_at: nil).group_by_period(period, :created_at, time_zone: @time_zone, range: @time_range).count
38
38
  @top_searches = @searches.first(5)
39
39
  @bad_conversion_rate = @searches.sort_by { |s| [s["conversion_rate"].to_f, s["query"]] }.first(5).select { |s| s["conversion_rate"] < 50 }
40
40
  @conversion_rate_by_week = {}
41
41
  @searches_by_week.each do |week, searches_count|
42
- @conversion_rate_by_week[week] = searches_count > 0 ? (100.0 * @conversions_by_week[week] / searches_count).round : 0
42
+ @conversion_rate_by_week[week] = searches_count > 0 ? (100.0 * @converted_by_week[week] / searches_count).round : 0
43
43
  end
44
44
  end
45
45
 
@@ -87,7 +87,7 @@ module Searchjoy
87
87
  def set_searches
88
88
  @limit = params[:limit] || Searchjoy.top_searches
89
89
  relation = Searchjoy::Search
90
- .select("normalized_query, COUNT(*) as searches_count, COUNT(converted_at) as conversions_count, AVG(results_count) as avg_results_count")
90
+ .select("normalized_query, COUNT(*) as searches_count, COUNT(converted_at) as converted_count, AVG(results_count) as avg_results_count")
91
91
  .where(created_at: @time_range, search_type: @search_type)
92
92
  .group(:normalized_query)
93
93
  .order(searches_count: :desc, normalized_query: :asc)
@@ -95,7 +95,7 @@ module Searchjoy
95
95
  # get array of hashes for performance
96
96
  @searches = Searchjoy::Search.connection.select_all(relation.to_sql).to_a
97
97
  @searches.each do |search|
98
- search["conversion_rate"] = 100 * search["conversions_count"].to_i / search["searches_count"].to_f
98
+ search["conversion_rate"] = 100 * search["converted_count"].to_i / search["searches_count"].to_f
99
99
  end
100
100
  end
101
101
  end
@@ -4,6 +4,7 @@
4
4
  <title>Searchjoy</title>
5
5
 
6
6
  <meta charset="utf-8" />
7
+ <%= csp_meta_tag %>
7
8
 
8
9
  <style>
9
10
  body {
@@ -289,9 +290,9 @@
289
290
  </style>
290
291
 
291
292
  <% if defined?(Propshaft::Railtie) %>
292
- <%= javascript_include_tag "chartkick", "Chart.bundle", "searchjoy/litepicker", "searchjoy/application" %>
293
+ <%= javascript_include_tag "chartkick", "Chart.bundle", "searchjoy/litepicker", "searchjoy/application", nonce: true %>
293
294
  <% else %>
294
- <%= javascript_include_tag "searchjoy/application" %>
295
+ <%= javascript_include_tag "searchjoy/application", nonce: true %>
295
296
  <% end %>
296
297
  </head>
297
298
  <body>
@@ -314,7 +315,7 @@
314
315
  <%= @time_range.first.strftime("%b %-e, %Y") %> to <%= @time_range.last.strftime("%b %-e, %Y") %>
315
316
  </span>
316
317
  <span class="text-muted"><%= @time_zone.name.sub(" (US & Canada)", "") %></span>
317
- <script>
318
+ <%= javascript_tag nonce: true do %>
318
319
  var startDate = <%= raw json_escape(@time_range.first.to_json) %>;
319
320
  var endDate = <%= raw json_escape(@time_range.last.to_json) %>;
320
321
  new Litepicker({
@@ -337,7 +338,7 @@
337
338
  window.location.href = window.location.pathname + "?" + params.toString();
338
339
  }
339
340
  });
340
- </script>
341
+ <% end %>
341
342
  <% end %>
342
343
  </div>
343
344
  </div>
@@ -8,7 +8,7 @@
8
8
  <tr>
9
9
  <th>Query</th>
10
10
  <th class="num" style="width: 20%;"><%= link_to "Searches", searches_path(search_type: params[:search_type], **@time_params), class: ("active" if params[:sort] != "conversion_rate") %></th>
11
- <th class="num" style="width: 20%;">Conversions</th>
11
+ <th class="num" style="width: 20%;">Converted</th>
12
12
  <th class="num" style="width: 20%;"><%= link_to "%", searches_path(search_type: params[:search_type], sort: "conversion_rate", **@time_params), class: ("active" if params[:sort] == "conversion_rate") %></th>
13
13
  <th class="num" style="width: 20%;">Avg Results</th>
14
14
  </tr>
@@ -18,7 +18,7 @@
18
18
  <tr>
19
19
  <td><%= search["normalized_query"] %></td>
20
20
  <td class="num"><%= search["searches_count"] %></td>
21
- <td class="num"><%= search["conversions_count"] %></td>
21
+ <td class="num"><%= search["converted_count"] %></td>
22
22
  <td class="num"><%= number_to_percentage search["conversion_rate"].to_f, precision: 0 %></td>
23
23
  <td class="num"><%= search["avg_results_count"].to_f.round %></td>
24
24
  </tr>
@@ -23,7 +23,7 @@
23
23
  <table>
24
24
  <thead>
25
25
  <tr>
26
- <th>Low Conversions</th>
26
+ <th>Low Conversion Rate</th>
27
27
  <th class="num"><%= link_to "View all", searches_path(search_type: @search_type, sort: "conversion_rate", **@time_params) %></th>
28
28
  </tr>
29
29
  </thead>
@@ -45,4 +45,4 @@
45
45
 
46
46
  <h2>Volume</h2>
47
47
 
48
- <%= line_chart [{name: "Searches", data: @searches_by_week}, {name: "Conversions", data: @conversions_by_week}] %>
48
+ <%= line_chart [{name: "Searches", data: @searches_by_week}, {name: "Converted", data: @converted_by_week}] %>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <table id="stream"></table>
4
4
 
5
- <script>
5
+ <%= javascript_tag nonce: true do %>
6
6
  function load(element, path) {
7
7
  var request = new XMLHttpRequest();
8
8
  request.open("GET", path, true);
@@ -20,4 +20,4 @@
20
20
  setTimeout(fetchRecentSearches, 5 * 1000);
21
21
  }
22
22
  fetchRecentSearches();
23
- </script>
23
+ <% end %>
@@ -4,7 +4,7 @@ module Searchjoy
4
4
 
5
5
  initializer "searchjoy" do |app|
6
6
  if app.config.respond_to?(:assets)
7
- if defined?(Sprockets) && Sprockets::VERSION >= "4"
7
+ if defined?(Sprockets) && Sprockets::VERSION.to_i >= 4
8
8
  app.config.assets.precompile << "searchjoy/application.js"
9
9
  else
10
10
  # use a proc instead of a string
@@ -1,3 +1,3 @@
1
1
  module Searchjoy
2
- VERSION = "1.0.0"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/searchjoy.rb CHANGED
@@ -4,8 +4,8 @@ require "chartkick"
4
4
  require "groupdate"
5
5
 
6
6
  # modules
7
- require "searchjoy/track"
8
- require "searchjoy/version"
7
+ require_relative "searchjoy/track"
8
+ require_relative "searchjoy/version"
9
9
 
10
10
  module Searchjoy
11
11
  # time zone
@@ -44,19 +44,13 @@ module Searchjoy
44
44
  created_at: search.converted_at
45
45
  }
46
46
  end
47
- if ActiveRecord::VERSION::MAJOR >= 6
48
- Searchjoy::Conversion.insert_all(conversions)
49
- else
50
- Searchjoy::Conversion.transaction do
51
- Searchjoy::Conversion.create!(conversions)
52
- end
53
- end
47
+ Searchjoy::Conversion.insert_all(conversions)
54
48
  end
55
49
  end
56
50
  end
57
51
 
58
52
  if defined?(Rails)
59
- require "searchjoy/engine"
60
- else
61
- Searchjoy.attach_to_searchkick! if defined?(Searchkick)
53
+ require_relative "searchjoy/engine"
54
+ elsif defined?(Searchkick)
55
+ Searchjoy.attach_to_searchkick!
62
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchjoy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-10 00:00:00.000000000 Z
11
+ date: 2024-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chartkick
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
19
+ version: '5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '3.2'
26
+ version: '5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: groupdate
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '3'
33
+ version: '6'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '3'
40
+ version: '6'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: activerecord
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '5.2'
47
+ version: '6.1'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '5.2'
54
+ version: '6.1'
55
55
  description:
56
56
  email: andrew@ankane.org
57
57
  executables: []
@@ -91,14 +91,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - ">="
93
93
  - !ruby/object:Gem::Version
94
- version: '2.6'
94
+ version: '3.1'
95
95
  required_rubygems_version: !ruby/object:Gem::Requirement
96
96
  requirements:
97
97
  - - ">="
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  requirements: []
101
- rubygems_version: 3.3.7
101
+ rubygems_version: 3.5.11
102
102
  signing_key:
103
103
  specification_version: 4
104
104
  summary: Search analytics made easy