Module: Controllers::AcceleratedFileSending

Extended by:
ActiveSupport::Concern
Included in:
ApplicationController
Defined in:
app/concerns/controllers/accelerated_file_sending.rb

Overview

File sending with S3 redirect and optional nginx acceleration for local files

For S3-backed uploads: Redirects to presigned S3 URL (simple, reliable)
For local files: Uses nginx X-Sendfile when configured, otherwise streams via Rails

Usage:

Send an Upload model (S3-backed) - redirects to presigned URL

send_upload_accelerated(upload, download: true)

Send a local file - uses nginx acceleration if available

send_file_accelerated('/path/to/file.pdf', download: true)

Instance Method Summary collapse

Instance Method Details

#send_file_accelerated(file_path, download: false, mime_type: nil, file_name: nil, delete_after_send: false, preserve_source: false, encoding: 'utf8') ⇒ Object

Send a local file using server acceleration if available

Parameters:

  • file_path (String, Pathname)

    Path to the file

  • download (Boolean) (defaults to: false)

    Force download vs inline display

  • mime_type (String) (defaults to: nil)

    Override the MIME type

  • file_name (String) (defaults to: nil)

    Override the filename

  • delete_after_send (Boolean) (defaults to: false)

    Delete file after sending (non-accelerated only)

  • preserve_source (Boolean) (defaults to: false)

    Copy instead of move for acceleration

  • encoding (String) (defaults to: 'utf8')

    Content encoding



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'app/concerns/controllers/accelerated_file_sending.rb', line 49

def send_file_accelerated(file_path, download: false, mime_type: nil, file_name: nil, delete_after_send: false, preserve_source: false, encoding: 'utf8')
  unless File.exist?(file_path)
    ErrorReporting.from_controller(self).informational(
      'File not found for download',
      file_path: file_path.to_s,
      reason: 'file_missing'
    )
    head :not_found
    return
  end

  local_file_name = File.basename(file_path)
  disposition = download ? 'attachment' : 'inline'
  mime_type ||= Marcel::MimeType.for(Pathname.new(file_path))
  file_name ||= local_file_name

  # Preserve files from public folder
  preserve_source = true if file_path.to_s.starts_with?(Rails.public_path.to_s)

  x_sendfile_header = Rails.application.config.action_dispatch.x_sendfile_header
  temp_storage_path = Rails.application.config.x.temp_storage_path
  temp_storage_nginx_prefix = Rails.application.config.x.temp_storage_nginx_prefix

  if x_sendfile_header && temp_storage_path.present? && temp_storage_nginx_prefix.present?
    send_local_file_accelerated(file_path, local_file_name, disposition, mime_type, file_name, x_sendfile_header, temp_storage_path, preserve_source, temp_storage_nginx_prefix)
  else
    data = File.read(file_path)
    send_data(data, filename: file_name, type: mime_type, disposition:, encoding:)
    File.delete(file_path) if delete_after_send
  end
end

#send_upload_accelerated(upload, download: false, file_name: nil, expires_in: 1.day) ⇒ Object

Send an Upload model by redirecting to presigned S3 URL

Uses Upload#presigned_url which generates signed S3 URLs locally
without any network calls (pure AWS Sig V4 computation).

Parameters:

  • upload (Upload)

    The upload record to send

  • download (Boolean) (defaults to: false)

    Force download vs inline display

  • file_name (String) (defaults to: nil)

    Override the filename for downloads

  • expires_in (ActiveSupport::Duration) (defaults to: 1.day)

    URL expiration time (default: 1 day)



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'app/concerns/controllers/accelerated_file_sending.rb', line 27

def send_upload_accelerated(upload, download: false, file_name: nil, expires_in: 1.day)
  return head(:not_found) unless upload&.attachment_uid.present?

  signed_url = upload.presigned_url(expires_in:, download:, file_name:)

  if signed_url.present?
    redirect_to signed_url, allow_other_host: true
  else
    # Fallback: stream directly if presigned_url not available
    disposition = download ? 'attachment' : 'inline'
    send_data upload.attachment.data, filename: file_name || upload.attachment_name, type: upload.mime_type, disposition:
  end
end