today_ai_weather/app/models/city.rb
songtianlun 6eca78da8d fix: update JSONB handling for ahoy events
- Change query conditions in City model to use the
  `properties::jsonb` syntax for compatibility.
- Update WeatherArt model's event counting to reflect
  the same JSONB handling for consistency across models.

These changes ensure that the queries correctly access the
JSONB fields in the database, which enhances robustness
when handling different database adapters like Postgres
or SQLite. This fixes potential issues with ahoy events
not being counted accurately due to incorrect property access.
2025-01-27 01:05:16 +08:00

114 lines
3.7 KiB
Ruby

class City < ApplicationRecord
extend FriendlyId
friendly_id :slug_candidates, use: :slugged
belongs_to :country
has_many :weather_arts, dependent: :destroy
has_many :visits, class_name: "Ahoy::Visit", foreign_key: :city_id
has_many :events, class_name: "Ahoy::Event", foreign_key: :city_id
delegate :region, to: :country
validates :name, presence: true
validates :latitude, presence: true
validates :longitude, presence: true
delegate :region, to: :country
scope :by_region, ->(region_id) { joins(:country).where(countries: { region_id: region_id }) }
scope :by_country, ->(country_id) { where(country_id: country_id) }
scope :active, -> { where(active: true) }
scope :by_popularity, -> {
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
joins("LEFT JOIN ahoy_events ON json_extract(ahoy_events.properties, '$.city_id') = cities.id
AND json_extract(ahoy_events.properties, '$.event_type') = 'city_view'")
.group("cities.id")
.select("cities.*, COUNT(ahoy_events.id) as visit_count")
.order("visit_count DESC")
else
joins("LEFT JOIN ahoy_events ON (ahoy_events.properties::jsonb->>'city_id')::integer = cities.id
AND ahoy_events.properties::jsonb->>'event_type' = 'city_view'")
.group("cities.id")
.select("cities.*, COUNT(ahoy_events.id) as visit_count")
.order("visit_count DESC")
end
}
scope :least_popular_active, -> {
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
active
.joins("LEFT JOIN ahoy_events ON json_extract(ahoy_events.properties, '$.city_id') = cities.id
AND json_extract(ahoy_events.properties, '$.event_type') = 'city_view'")
.group("cities.id")
.select("cities.*, COUNT(ahoy_events.id) as visit_count")
.order("visit_count ASC, cities.name ASC")
else
active
.joins("LEFT JOIN ahoy_events ON (ahoy_events.properties::jsonb->>'city_id')::integer = cities.id
AND ahoy_events.properties::jsonb->>'event_type' = 'city_view'")
.group("cities.id")
.select("cities.*, COUNT(ahoy_events.id) as visit_count")
.order("visit_count ASC, cities.name ASC")
end
}
def to_s
name
end
def slug_candidates
[
:name,
[ :country, :name ]
]
end
def localized_name
I18n.t("cities.#{name.parameterize.underscore}")
end
def full_name
"#{name}, #{country}"
end
def should_generate_new_friendly_id?
name_changed? || super
end
def self.ransackable_associations(auth_object = nil)
[ "weather_arts" ]
end
def self.ransackable_attributes(auth_object = nil)
[ "active", "country_id", "created_at", "id", "id_value", "last_image_generation", "last_weather_fetch", "latitude", "longitude", "name", "priority", "region", "slug", "timezone", "updated_at" ]
end
def last_weather_fetch
# latest_weather_art&.created_at
Rails.cache.fetch("city/#{id}/last_weather_fetch", expires_in: 1.hour) do
latest_weather_art&.created_at
end
end
def last_image_generation
# latest_weather_art&.image&.created_at
Rails.cache.fetch("city/#{id}/last_image_generation", expires_in: 1.hour) do
latest_weather_art&.image&.created_at
end
end
def latest_weather_art
weather_arts.order(weather_date: :desc).first
end
def view_count
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
Ahoy::Event.where("json_extract(properties, '$.event_type') = 'city_view' AND json_extract(properties, '$.city_id') = ?", self.id).count
else
Ahoy::Event.where("properties::jsonb->>'event_type' = 'city_view' AND (properties::jsonb->>'city_id')::integer = ?", self.id).count
end
end
end