Merge branch 'fix/image-upload' into feat/image-upload

This commit is contained in:
kbe
2025-10-01 08:37:57 +02:00
11 changed files with 274 additions and 78 deletions

View File

@@ -29,7 +29,9 @@ class Event < ApplicationRecord
# === Callbacks ===
before_validation :generate_slug, if: :should_generate_slug?
before_validation :geocode_address, if: :should_geocode_address?
before_update :handle_image_replacement, if: :image_attached?
# Validations for Event attributes
# Basic information
@@ -67,19 +69,98 @@ class Event < ApplicationRecord
# === Instance Methods ===
# Get image for display - handles both uploaded files and URLs
def event_image_variant(size = :medium)
if image.attached?
case size
when :large
image.variant(resize_to_limit: [1200, 630])
when :medium
image.variant(resize_to_limit: [800, 450])
when :small
image.variant(resize_to_limit: [400, 225])
else
image
# Generate SEO-friendly slug from name, venue name, and city
def generate_slug
return if name.blank? && venue_name.blank? && venue_address.blank?
# Extract city from venue address
city = extract_city_from_address(venue_address)
# Build slug parts
slug_parts = []
slug_parts << name if name.present?
slug_parts << venue_name if venue_name.present?
slug_parts << city if city.present?
# Generate slug using Rails' parameterize
slug_value = slug_parts.join("-").parameterize
# Ensure minimum length
if slug_value.length < 3
slug_value = "event-#{Time.current.to_i}".parameterize
end
# Make sure slug is unique
base_slug = slug_value
counter = 1
while Event.where.not(id: id).where(slug: slug_value).exists?
slug_value = "#{base_slug}-#{counter}".parameterize
counter += 1
end
self.slug = slug_value
end
# Check if slug should be generated
def should_generate_slug?
# Generate slug if it's blank or if it's a new record
slug.blank? || new_record?
end
# Extract city from address
def extract_city_from_address(address)
return "" if address.blank?
# Look for French postal code pattern (5 digits) + city
match = address.match(/(\d{5})\s+([^,]+)/)
if match
return match[2].strip
end
# Fallback: extract last part after comma (assume it's city)
parts = address.split(",")
if parts.length > 1
return parts[parts.length - 1].strip
end
# Another fallback: look for common French city indicators
city_indicators = [ "Paris", "Lyon", "Marseille", "Toulouse", "Nice", "Nantes", "Strasbourg", "Montpellier", "Bordeaux", "Lille" ]
for city in city_indicators
if address.downcase.include?(city.downcase)
return city
end
end
""
end
# Get image URL prioritizing old image field if it exists
def display_image_url
# First check if old image field exists and has a value
return self[:image] if self[:image].present?
# Fall back to attached image
return nil unless image.attached?
# Return the URL for the attached image
Rails.application.routes.url_helpers.rails_blob_url(image, only_path: true)
end
# Get image variants for different display sizes
def event_image_variant(size = :medium)
# For old image field, return the URL directly
return self[:image] if self[:image].present?
# For attached images, process variants
return nil unless image.attached?
case size
when :large
image.variant(resize_to_limit: [ 1200, 630 ])
when :medium
image.variant(resize_to_limit: [ 800, 450 ])
when :small
image.variant(resize_to_limit: [ 400, 225 ])
else
# Fallback to URL-based image
image_url.presence
@@ -100,6 +181,11 @@ class Event < ApplicationRecord
end
end
# Check if event has any image (old field or attached)
def has_image?
self[:image].present? || image.attached?
end
# Check if coordinates were successfully geocoded or are fallback coordinates
def geocoding_successful?
coordinates_look_valid?
@@ -203,6 +289,19 @@ class Event < ApplicationRecord
private
# Check if image is attached for the callback
def image_attached?
image.attached?
end
# Handle image replacement when a new image is uploaded
def handle_image_replacement
# Clear the old image field if a new image is being attached
if image.attached?
self[:image] = nil
end
end
# Determine if we should perform server-side geocoding
def should_geocode_address?
# Don't geocode if address is blank