refactor: update popularity scope and controller logic

- Change `by_popularity` method in `City` model to use `start_time` for filtering views.
- Update `by_popularity` in `WeatherArt` model to limit results and incorporate the correct popularity calculation.
- Adjust `HomeController` to define `@popular_shuffle_arts` and `@latest_arts` with appropriate scopes.

These changes improve the accuracy of popularity retrieval for both cities and weather arts, simplifying the logic in the controller and leveraging updated model methods for performance.
This commit is contained in:
songtianlun 2025-02-12 17:54:57 +08:00
parent 940f1a8f76
commit 0a6926421f
5 changed files with 25 additions and 14 deletions

View File

@ -40,7 +40,7 @@ ActiveAdmin.register_page "Ahoy Dashboard" do
columns do columns do
column do column do
panel "今日热门城市" do panel "今日热门城市" do
table_for City.by_popularity(:today, 10) do table_for City.by_popularity(:day, 10) do
column("城市") { |city| link_to(city.name, admin_city_path(city)) } column("城市") { |city| link_to(city.name, admin_city_path(city)) }
column("访问量") { |city| city.view_count } column("访问量") { |city| city.view_count }
end end

View File

@ -1,6 +1,7 @@
class HomeController < ApplicationController class HomeController < ApplicationController
def index def index
@latest_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(20).shuffle.last(10) @popular_shuffle_arts = WeatherArt.by_popularity(10).shuffle.last(6)
@latest_arts = WeatherArt.latest(12)
@featured_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(5) @featured_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(5)
set_meta_tags( set_meta_tags(
title: "AI-Generated Weather Art", title: "AI-Generated Weather Art",

View File

@ -25,18 +25,18 @@ class City < ApplicationRecord
# 在 City 模型中 # 在 City 模型中
scope :by_popularity, ->(period = :year, limit = 100) { scope :by_popularity, ->(period = :year, limit = 100) {
# 根据时间周期确定时间范围 # 根据时间周期确定时间范围
time_range = start_time =
case period.to_sym case period.to_sym
when :today when :day
Time.current.beginning_of_day..Time.current.end_of_day 1.day.ago
when :week when :week
Time.current.beginning_of_week..Time.current.end_of_week 1.week.ago
when :month when :month
Time.current.beginning_of_month..Time.current.end_of_month 1.month.ago
when :year when :year
Time.current.beginning_of_year..Time.current.end_of_year 1.year.ago
else else
Time.current.beginning_of_year..Time.current.end_of_year 1.year.ago
end end
# 根据数据库类型构建不同的查询 # 根据数据库类型构建不同的查询
@ -45,14 +45,14 @@ class City < ApplicationRecord
LEFT JOIN ahoy_events ON LEFT JOIN ahoy_events ON
json_extract(ahoy_events.properties, '$.city_id') = cities.id json_extract(ahoy_events.properties, '$.city_id') = cities.id
AND json_extract(ahoy_events.properties, '$.event_type') = 'city_view' AND json_extract(ahoy_events.properties, '$.event_type') = 'city_view'
AND ahoy_events.time BETWEEN '#{time_range.begin}' AND '#{time_range.end}' AND ahoy_events.time > '#{start_time}'
SQL SQL
else else
joins(<<-SQL.squish) joins(<<-SQL.squish)
LEFT JOIN ahoy_events ON LEFT JOIN ahoy_events ON
(ahoy_events.properties::jsonb->>'city_id')::integer = cities.id (ahoy_events.properties::jsonb->>'city_id')::integer = cities.id
AND ahoy_events.properties::jsonb->>'event_type' = 'city_view' AND ahoy_events.properties::jsonb->>'event_type' = 'city_view'
AND ahoy_events.time BETWEEN '#{time_range.begin}' AND '#{time_range.end}' AND ahoy_events.time > '#{start_time}'
SQL SQL
end end

View File

@ -12,19 +12,23 @@ class WeatherArt < ApplicationRecord
validates :weather_date, presence: true validates :weather_date, presence: true
validates :city_id, presence: true validates :city_id, presence: true
scope :by_popularity, -> { scope :latest, ->(limit: 100) {
order(created_at: :desc).limit(limit)
}
scope :by_popularity, ->(limit: 100) {
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite" if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
joins("LEFT JOIN ahoy_events ON json_extract(ahoy_events.properties, '$.weather_art_id') = weather_arts.id joins("LEFT JOIN ahoy_events ON json_extract(ahoy_events.properties, '$.weather_art_id') = weather_arts.id
AND json_extract(ahoy_events.properties, '$.event_type') = 'weather_art_view'") AND json_extract(ahoy_events.properties, '$.event_type') = 'weather_art_view'")
.group("weather_arts.id") .group("weather_arts.id")
.select("weather_arts.*, COUNT(ahoy_events.id) as visit_count") .select("weather_arts.*, COUNT(ahoy_events.id) as visit_count")
.order("visit_count DESC") .order("visit_count DESC").limit(limit)
else else
joins("LEFT JOIN ahoy_events ON (ahoy_events.properties::jsonb->>'weather_art_id')::integer = weather_arts.id joins("LEFT JOIN ahoy_events ON (ahoy_events.properties::jsonb->>'weather_art_id')::integer = weather_arts.id
AND ahoy_events.properties::jsonb->>'event_type' = 'weather_art_view'") AND ahoy_events.properties::jsonb->>'event_type' = 'weather_art_view'")
.group("weather_arts.id") .group("weather_arts.id")
.select("weather_arts.*, COUNT(ahoy_events.id) as visit_count") .select("weather_arts.*, COUNT(ahoy_events.id) as visit_count")
.order("visit_count DESC") .order("visit_count DESC").limit(limit)
end end
} }

View File

@ -5,6 +5,12 @@ class BatchGenerateWeatherArtsWorker
SLEEP_DURATION = 120.seconds SLEEP_DURATION = 120.seconds
BATCH_SIZE = 20 BATCH_SIZE = 20
module ProcessType
DO_NOTHING = 0
GET_WEATHER_WITH_GENERATE_AI_ART = 1
GET_WEATHER_ONLY = 2
end
def perform(*args) def perform(*args)
start_time = Time.current start_time = Time.current
cities_to_process = get_eligible_cities.shuffle.take(BATCH_SIZE) cities_to_process = get_eligible_cities.shuffle.take(BATCH_SIZE)