Rails ActiveStorage文件处理:仅即时处理还是支持上传时?视频压缩咨询
Hey there! Great question—ActiveStorage absolutely works for video uploads and compression, it just doesn’t have this feature built right into the core. Let me walk you through how to set this up, since it’s similar to the Shrine+ffmpeg workflow you’re already familiar with.
Key Background
ActiveStorage handles file storage, model associations, and basic preview generation out of the box, but video compression (a resource-heavy task) needs to be handled separately with background jobs and ffmpeg, just like you did with Shrine.
Step-by-Step Implementation
1. Set Up ActiveStorage for Video Uploads
First, make sure you’ve got ActiveStorage configured (run rails active_storage:install and migrate if you haven’t already). Then add attachments to your model—you can choose to keep both original and compressed versions, or replace the original:
# app/models/video.rb class Video < ApplicationRecord has_one_attached :original_video has_one_attached :compressed_video # Optional: retain original for backup end
2. Use Background Jobs for Compression
Video compression is slow—never run it during a web request. Use a background job processor like Sidekiq or Delayed Job to handle this after upload.
Here’s an example Sidekiq job that uses ffmpeg to compress the video (tweak the ffmpeg parameters to match your quality/size needs):
# app/jobs/video_compression_job.rb class VideoCompressionJob < ApplicationJob queue_as :video_processing def perform(video) # Download original video from ActiveStorage to a temp file original_temp = Tempfile.new(["original", ".mp4"], encoding: 'ascii-8bit') original_temp.write(video.original_video.download) original_temp.close # Create temp file for compressed output compressed_temp = Tempfile.new(["compressed", ".mp4"], encoding: 'ascii-8bit') # Run ffmpeg compression command # This example uses H.264 codec with balanced quality/size (CRF 28) system( "ffmpeg -i #{original_temp.path} " \ "-vcodec libx264 -crf 28 -preset medium " \ "-acodec aac -b:a 128k " \ "#{compressed_temp.path}" ) # Attach compressed video to the model video.compressed_video.attach( io: File.open(compressed_temp.path), filename: "compressed_#{video.original_video.filename.base}.mp4", content_type: "video/mp4" ) # Clean up temp files to avoid clutter original_temp.unlink compressed_temp.unlink rescue => e # Log or alert on failure (corrupted files/unsupported formats happen!) Rails.logger.error "Video compression failed for video #{video.id}: #{e.message}" end end
3. Trigger the Job After Upload
Add a callback to your Video model to kick off the compression job once the original video is attached:
# app/models/video.rb class Video < ApplicationRecord has_one_attached :original_video has_one_attached :compressed_video after_create_commit :trigger_compression_job private def trigger_compression_job VideoCompressionJob.perform_later(self) if original_video.attached? end end
4. Bonus: Generate Video Previews
Since you mentioned preview generation, you can extend the job to create a thumbnail at the same time using ffmpeg:
# Inside VideoCompressionJob#perform, after compression logic # Generate a thumbnail from the 1st second of the video thumbnail_temp = Tempfile.new(["thumbnail", ".jpg"], encoding: 'ascii-8bit') system("ffmpeg -i #{original_temp.path} -ss 00:00:01 -vframes 1 #{thumbnail_temp.path}") # Attach thumbnail to the model (add `has_one_attached :thumbnail` to Video first) video.thumbnail.attach( io: File.open(thumbnail_temp.path), filename: "thumbnail_#{video.original_video.filename.base}.jpg", content_type: "image/jpeg" ) thumbnail_temp.unlink
Important Notes
- Install ffmpeg: Make sure your server has ffmpeg installed (most hosting providers support this, or install via
apt-get install ffmpegon Debian/Ubuntu). - Storage Choices: If you don’t need the original video, use
video.original_video.purgebefore attaching the compressed file to save space. - Error Handling: Add alerts (like Slack notifications) for failed jobs—video processing can fail for corrupted files or unsupported formats.
Final Takeaway
ActiveStorage is a solid replacement for Shrine here. It handles the heavy lifting of file storage and model associations, while you can reuse your existing ffmpeg and background job knowledge to handle compression. It’s flexible and integrates seamlessly with Rails’ ecosystem.
内容的提问来源于stack exchange,提问作者R4ttlesnake

