2025-01-19 12:21:00 +08:00
|
|
|
class City < ApplicationRecord
|
|
|
|
extend FriendlyId
|
2025-01-22 14:04:58 +08:00
|
|
|
friendly_id :slug_candidates, use: :slugged
|
2025-01-21 18:27:26 +08:00
|
|
|
belongs_to :country
|
2025-01-19 12:21:00 +08:00
|
|
|
|
|
|
|
has_many :weather_arts, dependent: :destroy
|
|
|
|
|
2025-01-27 00:43:18 +08:00
|
|
|
has_many :visits, class_name: "Ahoy::Visit", foreign_key: :city_id
|
|
|
|
has_many :events, class_name: "Ahoy::Event", foreign_key: :city_id
|
|
|
|
|
2025-01-23 14:10:13 +08:00
|
|
|
delegate :region, to: :country
|
|
|
|
|
2025-01-19 12:21:00 +08:00
|
|
|
validates :name, presence: true
|
|
|
|
validates :latitude, presence: true
|
|
|
|
validates :longitude, presence: true
|
|
|
|
|
2025-01-21 18:27:26 +08:00
|
|
|
delegate :region, to: :country
|
|
|
|
|
2025-01-22 14:04:58 +08:00
|
|
|
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) }
|
|
|
|
|
2025-01-27 00:43:18 +08:00
|
|
|
scope :by_popularity, -> {
|
2025-01-27 00:43:36 +08:00
|
|
|
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
|
2025-01-27 00:43:18 +08:00
|
|
|
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
|
2025-01-27 01:05:16 +08:00
|
|
|
joins("LEFT JOIN ahoy_events ON (ahoy_events.properties::jsonb->>'city_id')::integer = cities.id
|
|
|
|
AND ahoy_events.properties::jsonb->>'event_type' = 'city_view'")
|
2025-01-27 00:43:18 +08:00
|
|
|
.group("cities.id")
|
|
|
|
.select("cities.*, COUNT(ahoy_events.id) as visit_count")
|
|
|
|
.order("visit_count DESC")
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
2025-01-27 00:48:07 +08:00
|
|
|
scope :least_popular_active, -> {
|
2025-01-27 00:50:35 +08:00
|
|
|
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
|
2025-01-27 00:48:07 +08:00
|
|
|
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
|
2025-01-27 01:05:16 +08:00
|
|
|
.joins("LEFT JOIN ahoy_events ON (ahoy_events.properties::jsonb->>'city_id')::integer = cities.id
|
|
|
|
AND ahoy_events.properties::jsonb->>'event_type' = 'city_view'")
|
2025-01-27 00:48:07 +08:00
|
|
|
.group("cities.id")
|
|
|
|
.select("cities.*, COUNT(ahoy_events.id) as visit_count")
|
|
|
|
.order("visit_count ASC, cities.name ASC")
|
|
|
|
end
|
|
|
|
}
|
2025-01-28 01:43:59 +08:00
|
|
|
scope :most_popular_inactive, -> {
|
2025-01-28 01:44:07 +08:00
|
|
|
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
|
2025-01-28 01:43:59 +08:00
|
|
|
where(active: false)
|
|
|
|
.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("COUNT(ahoy_events.id) DESC, cities.name ASC")
|
|
|
|
else
|
|
|
|
where(active: false)
|
|
|
|
.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("COUNT(ahoy_events.id) DESC, cities.name ASC")
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
2025-01-27 00:48:07 +08:00
|
|
|
|
2025-01-21 18:27:26 +08:00
|
|
|
def to_s
|
|
|
|
name
|
|
|
|
end
|
|
|
|
|
2025-01-22 14:04:58 +08:00
|
|
|
def slug_candidates
|
|
|
|
[
|
|
|
|
:name,
|
|
|
|
[ :country, :name ]
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
2025-01-21 18:27:26 +08:00
|
|
|
def localized_name
|
2025-01-28 01:49:13 +08:00
|
|
|
I18n.t("cities.#{name.parameterize.underscore}", default: name)
|
2025-01-21 18:27:26 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def full_name
|
|
|
|
"#{name}, #{country}"
|
|
|
|
end
|
|
|
|
|
2025-01-19 12:21:00 +08:00
|
|
|
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)
|
2025-01-25 00:54:23 +08:00
|
|
|
[ "active", "country_id", "created_at", "id", "id_value", "last_image_generation", "last_weather_fetch", "latitude", "longitude", "name", "priority", "region", "slug", "timezone", "updated_at" ]
|
2025-01-19 12:21:00 +08:00
|
|
|
end
|
|
|
|
|
2025-01-23 23:59:48 +08:00
|
|
|
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
|
|
|
|
|
2025-01-20 18:02:28 +08:00
|
|
|
def latest_weather_art
|
|
|
|
weather_arts.order(weather_date: :desc).first
|
|
|
|
end
|
2025-01-27 00:43:18 +08:00
|
|
|
|
|
|
|
def view_count
|
2025-01-27 00:43:36 +08:00
|
|
|
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
|
2025-01-27 00:43:18 +08:00
|
|
|
Ahoy::Event.where("json_extract(properties, '$.event_type') = 'city_view' AND json_extract(properties, '$.city_id') = ?", self.id).count
|
|
|
|
else
|
2025-01-27 01:05:16 +08:00
|
|
|
Ahoy::Event.where("properties::jsonb->>'event_type' = 'city_view' AND (properties::jsonb->>'city_id')::integer = ?", self.id).count
|
2025-01-27 00:43:18 +08:00
|
|
|
end
|
|
|
|
end
|
2025-01-19 12:21:00 +08:00
|
|
|
end
|