feat: Complete hybrid image upload system with URL compatibility
- Add hybrid image system supporting both file uploads and URL images - Implement Active Storage for file uploads while preserving existing URL functionality - Update Event model with both has_one_attached :image and image_url virtual attribute - Create tabbed interface in event forms for upload/URL selection - Add JavaScript preview functionality for both upload and URL inputs - Fix promotion code validation issue in tests using distinct() to prevent duplicates - Update all views to use hybrid display methods prioritizing uploads over URLs - Update seeds file to use image_url attribute for compatibility - Ensure backward compatibility with existing events using URL images 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,10 @@ class Event < ApplicationRecord
|
||||
has_many :promotion_codes
|
||||
has_one_attached :image
|
||||
|
||||
|
||||
# === Virtual attribute for backward compatibility with image URLs ===
|
||||
attr_accessor :image_url
|
||||
|
||||
|
||||
# === Callbacks ===
|
||||
before_validation :geocode_address, if: :should_geocode_address?
|
||||
|
||||
@@ -34,8 +37,11 @@ class Event < ApplicationRecord
|
||||
validates :slug, presence: true, length: { minimum: 3, maximum: 100 }
|
||||
validates :description, presence: true, length: { minimum: 10, maximum: 2000 }
|
||||
validates :state, presence: true, inclusion: { in: states.keys }
|
||||
|
||||
# Image validation - handles both attachments and URLs
|
||||
validate :image_format, if: -> { image.attached? }
|
||||
validate :image_size, if: -> { image.attached? }
|
||||
validate :image_url_format, if: -> { image_url.present? && !image.attached? }
|
||||
|
||||
# Venue information
|
||||
validates :venue_name, presence: true, length: { maximum: 100 }
|
||||
@@ -61,17 +67,36 @@ class Event < ApplicationRecord
|
||||
|
||||
# === Instance Methods ===
|
||||
|
||||
# Get image variants for different display sizes
|
||||
# Get image for display - handles both uploaded files and URLs
|
||||
def event_image_variant(size = :medium)
|
||||
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])
|
||||
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
|
||||
end
|
||||
else
|
||||
# Fallback to URL-based image
|
||||
image_url.presence
|
||||
end
|
||||
end
|
||||
|
||||
# Check if event has any image (uploaded or URL)
|
||||
def has_image?
|
||||
image.attached? || image_url.present?
|
||||
end
|
||||
|
||||
# Get display image source (uploaded or URL)
|
||||
def display_image
|
||||
if image.attached?
|
||||
image
|
||||
else
|
||||
image_url
|
||||
end
|
||||
end
|
||||
|
||||
@@ -167,6 +192,15 @@ class Event < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
# Validate image URL format
|
||||
def image_url_format
|
||||
return unless image_url.present?
|
||||
|
||||
unless image_url.match?(/\Ahttps?:\/\/.+\.(jpg|jpeg|png|gif|webp)(\?.*)?\z/i)
|
||||
errors.add(:image_url, "doit être une URL valide vers une image (JPG, PNG, GIF, WebP)")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Determine if we should perform server-side geocoding
|
||||
|
||||
Reference in New Issue
Block a user