mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
Optimize stats page performance
This commit is contained in:
parent
7c1c42dfc1
commit
88909b3e9f
14 changed files with 56 additions and 12 deletions
1
Gemfile
1
Gemfile
|
|
@ -77,4 +77,5 @@ group :development do
|
|||
gem 'database_consistency', require: false
|
||||
gem 'foreman'
|
||||
gem 'rubocop-rails', require: false
|
||||
gem 'bullet'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ GEM
|
|||
brakeman (7.0.2)
|
||||
racc
|
||||
builder (3.3.0)
|
||||
bullet (8.0.8)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
bundler-audit (0.9.2)
|
||||
bundler (>= 1.2.0, < 3)
|
||||
thor (~> 1.0)
|
||||
|
|
@ -486,6 +489,7 @@ GEM
|
|||
unicode-display_width (3.1.4)
|
||||
unicode-emoji (~> 4.0, >= 4.0.4)
|
||||
unicode-emoji (4.0.4)
|
||||
uniform_notifier (1.17.0)
|
||||
uri (1.0.3)
|
||||
useragent (0.16.11)
|
||||
warden (1.2.9)
|
||||
|
|
@ -519,6 +523,7 @@ DEPENDENCIES
|
|||
aws-sdk-s3 (~> 1.177.0)
|
||||
bootsnap
|
||||
brakeman
|
||||
bullet
|
||||
bundler-audit
|
||||
capybara
|
||||
chartkick
|
||||
|
|
|
|||
|
|
@ -5,10 +5,30 @@ class StatsController < ApplicationController
|
|||
before_action :authenticate_active_user!, only: %i[update update_all]
|
||||
|
||||
def index
|
||||
@stats = current_user.stats.group_by(&:year).transform_values { |stats| stats.sort_by(&:updated_at).reverse }.sort.reverse
|
||||
@points_total = current_user.tracked_points.count
|
||||
@points_reverse_geocoded = current_user.total_reverse_geocoded_points
|
||||
@points_reverse_geocoded_without_data = current_user.total_reverse_geocoded_points_without_data
|
||||
@stats = current_user.stats.group_by(&:year).transform_values do |stats|
|
||||
stats.sort_by(&:updated_at).reverse
|
||||
end.sort.reverse
|
||||
|
||||
# Single aggregated query to replace 3 separate COUNT queries
|
||||
result = current_user.tracked_points.connection.execute(<<~SQL.squish)
|
||||
SELECT#{' '}
|
||||
COUNT(*) as total,
|
||||
COUNT(reverse_geocoded_at) as geocoded,
|
||||
COUNT(CASE WHEN geodata = '{}' THEN 1 END) as without_data
|
||||
FROM points#{' '}
|
||||
WHERE user_id = #{current_user.id}
|
||||
SQL
|
||||
|
||||
row = result.first
|
||||
@points_total = row['total'].to_i
|
||||
@points_reverse_geocoded = row['geocoded'].to_i
|
||||
@points_reverse_geocoded_without_data = row['without_data'].to_i
|
||||
|
||||
# Precompute year distance data to avoid N+1 queries in view
|
||||
@year_distances = {}
|
||||
@stats.each do |year, _stats|
|
||||
@year_distances[year] = Stat.year_distance(year, current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Trips::CalculateAllJob < ApplicationJob
|
||||
queue_as :default
|
||||
queue_as :trips
|
||||
|
||||
def perform(trip_id, distance_unit = 'km')
|
||||
Trips::CalculatePathJob.perform_later(trip_id)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Trips::CalculateCountriesJob < ApplicationJob
|
||||
queue_as :default
|
||||
queue_as :trips
|
||||
|
||||
def perform(trip_id, distance_unit)
|
||||
trip = Trip.find(trip_id)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Trips::CalculateDistanceJob < ApplicationJob
|
||||
queue_as :default
|
||||
queue_as :trips
|
||||
|
||||
def perform(trip_id, distance_unit)
|
||||
trip = Trip.find(trip_id)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Trips::CalculatePathJob < ApplicationJob
|
||||
queue_as :default
|
||||
queue_as :trips
|
||||
|
||||
def perform(trip_id)
|
||||
trip = Trip.find(trip_id)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ class Country < ApplicationRecord
|
|||
end
|
||||
|
||||
def self.names_to_iso_a2
|
||||
pluck(:name, :iso_a2).to_h
|
||||
Rails.cache.fetch('countries_names_to_iso_a2', expires_in: 1.day) do
|
||||
pluck(:name, :iso_a2).to_h
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</h2>
|
||||
<div class='my-10'>
|
||||
<%= column_chart(
|
||||
Stat.year_distance(year, current_user),
|
||||
@year_distances[year],
|
||||
height: '200px',
|
||||
suffix: " #{current_user.safe_settings.distance_unit}",
|
||||
xtitle: 'Days',
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@
|
|||
</div>
|
||||
<% end %>
|
||||
<%= column_chart(
|
||||
Stat.year_distance(year, current_user).map { |month_name, distance_meters|
|
||||
@year_distances[year].map { |month_name, distance_meters|
|
||||
[month_name, Stat.convert_distance(distance_meters, current_user.safe_settings.distance_unit).round(2)]
|
||||
},
|
||||
height: '200px',
|
||||
|
|
|
|||
|
|
@ -3,6 +3,15 @@
|
|||
require 'active_support/core_ext/integer/time'
|
||||
|
||||
Rails.application.configure do
|
||||
config.after_initialize do
|
||||
Bullet.enable = true
|
||||
Bullet.alert = true
|
||||
Bullet.bullet_logger = true
|
||||
Bullet.console = true
|
||||
Bullet.rails_logger = true
|
||||
Bullet.add_footer = true
|
||||
end
|
||||
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
||||
# In the development environment your application's code is reloaded any time
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ Rails.application.configure do
|
|||
# config.assets.css_compressor = :sass
|
||||
|
||||
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
||||
config.assets.compile = true
|
||||
config.assets.compile = false
|
||||
|
||||
config.assets.content_type = {
|
||||
geojson: 'application/geo+json'
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ require 'active_support/core_ext/integer/time'
|
|||
# and recreated between test runs. Don't rely on the data there!
|
||||
|
||||
Rails.application.configure do
|
||||
config.after_initialize do
|
||||
Bullet.enable = true
|
||||
Bullet.bullet_logger = true
|
||||
Bullet.raise = true # raise an error if n+1 query occurs
|
||||
end
|
||||
|
||||
# Settings specified here will take precedence over those in config/application.rb.
|
||||
|
||||
# While tests run files are not watched, reloading is not necessary.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
- imports
|
||||
- exports
|
||||
- stats
|
||||
- trips
|
||||
- tracks
|
||||
- reverse_geocoding
|
||||
- visit_suggesting
|
||||
|
|
|
|||
Loading…
Reference in a new issue