GET /api/v1/files/{id} with resume support
- Create FileDownloader service:
class FileDownloader
def download(file_id, expected_checksum:, resume_from: 0)
# Downloads to temp file
# Supports Range header for resume
# Returns path to downloaded file
end
end
- Download to temp directory (tmp/downloads/)
- Track partial download progress for resume capability
- Return downloaded file path for attachment
Verify downloaded files match manifest checksums
- Create ChecksumVerifier service:
class ChecksumVerifier
def verify!(file_path, expected_sha256)
actual = Digest::SHA256.file(file_path).hexdigest
expected = expected_sha256.delete_prefix("sha256:")
raise ChecksumMismatchError unless actual == expected
end
end
- Consider using MD5 since active storage uses MD5 for checksums
- Integrate verification before ActiveStorage attachment
- On mismatch: delete file, retry download (up to 3 attempts)
Ensure proper ActiveStorage setup for offline operation
- Verify config/storage.yml uses local disk:
local:
service: Disk
root: <%= Rails.root.join("storage") %>
- Set in config/environments/production.rb:
config.active_storage.service = :local
- Configure blob cleanup: old blobs purged when TopicFile destroyed
- Add storage/ to backup strategy
GET /api/v1/files/{id} with resume support
Verify downloaded files match manifest checksums
Ensure proper ActiveStorage setup for offline operation
local:
service: Disk
root: <%= Rails.root.join("storage") %>
config.active_storage.service = :local