You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails Active Storage多附件关联:非MP4视频转码回调实现需求

完整解决方案

针对你需要给Cloud模型添加视频转码回调的需求,我整理了一套可行的实现方案,分为模型修改、Sidekiq Worker编写和关键注意事项三部分:

1. 更新Cloud模型

我们使用after_commit回调来处理,因为Active Storage的附件会在记录提交后才完成保存,这样能确保我们拿到已持久化的视频附件。同时我们会过滤掉已处理过的视频,只针对新添加的非MP4格式视频触发转码任务:

class Cloud < ApplicationRecord
  has_many_attached :images
  has_many_attached :videos

  # 保留原有的验证规则
  validates :images, content_type: { in: ['image/png', 'image/jpg', 'image/jpeg', 'image/gif'], message: 'should be of type png, jpg, jpeg and gif.' }
  validates :videos, content_type: { in: ['video/mp4', 'video/x-flv', 'video/x-msvideo', 'video/x-ms-wmv', 'video/avi', 'video/quicktime'], message: 'should be of type mp4, x-flv, x-msvideo, x-ms-wmv, avi and quicktime(mov).' }
  validates :videos, size: { greater_than: 1.kilobytes, message: 'size is invalid' }
  validates :images, size: { greater_than: 1.kilobytes, message: 'size is invalid' }

  # 提交后触发转码任务,支持创建和更新场景
  after_commit :queue_video_transcoding, on: [:create, :update]

  private

  def queue_video_transcoding
    # 遍历所有视频附件,筛选需要转码的目标
    videos.each do |video|
      # 只处理新上传的、且不是MP4格式的视频
      next unless video.previously_new_record? && video.content_type != 'video/mp4'

      # 将转码任务推入Sidekiq队列,传入Blob ID以便Worker定位视频
      VideoTranscodingWorker.perform_async(video.blob.id)
    end
  end
end

2. 创建视频转码Worker

接下来编写Sidekiq Worker来执行FFmpeg转码逻辑,Worker会负责下载原视频、转码为MP4、替换原附件的内容:

创建app/workers/video_transcoding_worker.rb文件:

class VideoTranscodingWorker
  include Sidekiq::Worker

  def perform(blob_id)
    blob = ActiveStorage::Blob.find(blob_id)
    # 下载原视频到临时文件
    original_temp_file = blob.open

    # 创建转码后的临时MP4文件
    transcoded_temp_file = Tempfile.new(["transcoded_#{blob.filename.base}", '.mp4'], binmode: true)

    begin
      # 执行FFmpeg转码命令,这里用了通用的H.264编码参数,你可以根据需求调整(比如分辨率、比特率)
      # 注意:必须确保服务器已经安装FFmpeg
      system(
        'ffmpeg',
        '-i', original_temp_file.path,
        '-c:v', 'libx264',
        '-c:a', 'aac',
        '-strict', 'experimental',
        transcoded_temp_file.path,
        exception: true # 命令失败时抛出异常,让Sidekiq自动重试
      )

      # 替换原Blob的内容为转码后的MP4
      blob.open do |file|
        file.binmode
        file.write(transcoded_temp_file.read)
        file.rewind
      end

      # 更新Blob的元数据,标记为MP4格式
      blob.update!(
        content_type: 'video/mp4',
        filename: "#{blob.filename.base}.mp4"
      )
    ensure
      # 无论转码成功或失败,都清理临时文件
      original_temp_file.close!
      transcoded_temp_file.close!
    end
  end
end

3. 关键注意事项

  • FFmpeg安装:服务器必须安装FFmpeg才能执行转码。Ubuntu可以用sudo apt-get install ffmpeg,macOS用brew install ffmpeg。
  • 错误重试:Sidekiq会自动重试失败的任务,你可以在Worker里添加日志记录,方便排查转码失败的原因。
  • 性能优化:视频转码是CPU密集型操作,建议调整Sidekiq的并发数,避免占用过多服务器资源;如果转码任务多,考虑用专门的转码服务器处理。
  • 存储权限:确保Sidekiq进程有访问Active Storage存储服务(比如本地存储、S3等)的权限,否则会无法下载或上传文件。

内容的提问来源于stack exchange,提问作者Vishal G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:08:44