- Create VotesController to manage voting actions - Implement Vote model with polymorphic associations - Add vote buttons to the city and weather art views - Integrate vote counting and user vote tracking - Define routes for the votes resource This commit sets up a voting mechanism for cities and weather arts, allowing users to upvote or downvote. It includes seamless integration of user sessions to track individual votes, ensuring votes can be modified or deleted based on user interaction.
145 lines
4.8 KiB
Ruby
145 lines
4.8 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
|
|
}
|
|
scope :most_popular_inactive, -> {
|
|
if ActiveRecord::Base.connection.adapter_name.downcase == "sqlite"
|
|
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
|
|
}
|
|
|
|
has_many :votes, as: :votable, dependent: :destroy
|
|
|
|
def to_s
|
|
name
|
|
end
|
|
|
|
def slug_candidates
|
|
[
|
|
:name,
|
|
[ :country, :name ]
|
|
]
|
|
end
|
|
|
|
def localized_name
|
|
I18n.t("cities.#{name.parameterize.underscore}", default: name)
|
|
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
|
|
|
|
def vote_counts
|
|
{
|
|
upvotes: votes.upvote.count,
|
|
downvotes: votes.downvote.count
|
|
}
|
|
end
|
|
|
|
def user_vote(user_session)
|
|
votes.find_by(user_session: user_session)&.vote_type
|
|
end
|
|
|
|
end
|