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 +4 -4
- data/CHANGELOG.md +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +12 -5
- data/app/controllers/searchjoy/searches_controller.rb +4 -4
- data/app/views/layouts/searchjoy/application.html.erb +5 -4
- data/app/views/searchjoy/searches/index.html.erb +2 -2
- data/app/views/searchjoy/searches/overview.html.erb +2 -2
- data/app/views/searchjoy/searches/stream.html.erb +2 -2
- data/lib/searchjoy/engine.rb +1 -1
- data/lib/searchjoy/version.rb +1 -1
- data/lib/searchjoy.rb +6 -12
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6e0ac0fd71243df3a3395c6ab793fe20d523ed435634b3adf73c44ac58aa167
|
4
|
+
data.tar.gz: 83708806572742373d3531750d867bdf9c4338df15546f4361e8d0b927330099
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/README.md
CHANGED
@@ -7,14 +7,14 @@ Search analytics made easy
|
|
7
7
|
[](https://searchjoy.dokkuapp.com/)
|
8
8
|
|
9
9
|
- view searches in real-time
|
10
|
-
- track
|
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
|
-
[](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).
|
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
|
-
|
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
|
-
@
|
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 * @
|
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
|
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["
|
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
|
-
|
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
|
-
|
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%;">
|
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["
|
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
|
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: "
|
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
|
-
|
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
|
-
|
23
|
+
<% end %>
|
data/lib/searchjoy/engine.rb
CHANGED
@@ -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 >=
|
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
|
data/lib/searchjoy/version.rb
CHANGED
data/lib/searchjoy.rb
CHANGED
@@ -4,8 +4,8 @@ require "chartkick"
|
|
4
4
|
require "groupdate"
|
5
5
|
|
6
6
|
# modules
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
-
|
60
|
-
|
61
|
-
Searchjoy.attach_to_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.
|
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:
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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: '
|
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.
|
101
|
+
rubygems_version: 3.5.11
|
102
102
|
signing_key:
|
103
103
|
specification_version: 4
|
104
104
|
summary: Search analytics made easy
|