Dateien in Supabase-Buckets mit Ruby exportieren
Supabase bietet mit seinem Bucket-System eine Cloud-Storage-Lösung. Mit den integrierten HTTP-Bibliotheken von Ruby können Sie mit Supabase Storage interagieren. In diesem Leitfaden zeigen wir, wie Sie Dateien über die REST API in Supabase-Storage-Buckets exportieren.
Voraussetzungen
Stellen Sie vor dem Start sicher, dass Sie über Folgendes verfügen:
- Ruby 2.7 oder höher installiert
- Ein Supabase-Konto und ein Projekt mit aktiviertem Storage
- Grundkenntnisse in der Ruby-Programmierung
- Die URL Ihres Supabase-Projekts, den Publishable Key oder den Legacy-Anon-Key des Projekts sowie das Access-JWT eines angemeldeten Benutzers
- Storage-Policies, die diesem Benutzer die erforderlichen Berechtigungen für insert, select und delete gewähren
Ihre Umgebung einrichten
Erstellen Sie ein neues Ruby-Projekt und richten Sie die erforderlichen Abhängigkeiten ein. Einige
Bibliotheken wie net/http und json sind zwar in Ruby enthalten, wir führen sie aber der
Klarheit halber auf und ergänzen mime-types, um die Content-Types von Dateien zu bestimmen:
mkdir supabase-storage-demo
cd supabase-storage-demo
bundle init
Fügen Sie Ihrem Gemfile die folgenden Gems hinzu:
source 'https://rubygems.org'
# Net/http and JSON are part of Ruby's standard library
gem 'mime-types'
Installieren Sie die Abhängigkeiten:
bundle install
Einen REST-API-Client in Ruby konfigurieren
Wir erstellen mit Net::HTTP aus Ruby einen kleinen Client, der mit der Supabase Storage REST API interagiert. Der Projektschlüssel identifiziert das Projekt; das separate Benutzer-JWT bestimmt den Zugriff des Benutzers gemäß den Storage-Policies. Bewahren Sie beides in Umgebungsvariablen auf und erneuern Sie die Benutzersitzung, wenn sie abläuft.
require 'net/http'
require 'json'
require 'mime/types'
class SupabaseStorage
def initialize(project_url, api_key, access_token)
@project_url = project_url.chomp('/')
@api_key = api_key
@access_token = access_token
@storage_url = "#{@project_url}/storage/v1"
end
private
def headers
{
'Authorization' => "Bearer #{@access_token}",
'apikey' => @api_key
}
end
def make_request(uri, request)
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
response = http.request(request)
unless response.is_a?(Net::HTTPSuccess)
raise "Storage request failed (HTTP #{response.code})"
end
response
end
end
def encode_segment(value)
URI.encode_www_form_component(value).gsub('+', '%20')
end
def encode_path(path)
path.split('/').map { |segment| encode_segment(segment) }.join('/')
end
public
# Upload a file to a specific bucket and destination path
def upload_file(bucket_name, file_path, destination_path)
uri = URI("#{@storage_url}/object/#{encode_segment(bucket_name)}/#{encode_path(destination_path)}")
request = Net::HTTP::Post.new(uri)
headers.each { |key, value| request[key] = value }
# Open the file in binary mode and set up the request stream
File.open(file_path, 'rb') do |file|
request.body_stream = file
request['Content-Type'] = MIME::Types.type_for(file_path).first&.to_s || 'application/octet-stream'
request['Content-Length'] = File.size(file_path).to_s
response = make_request(uri, request)
JSON.parse(response.body)
end
rescue StandardError => e
{ 'error' => e.message }
end
# List one page of immediate children of a prefix
def list_files(bucket_name, path = '', limit: 100, offset: 0)
uri = URI("#{@storage_url}/object/list/#{encode_segment(bucket_name)}")
request = Net::HTTP::Post.new(uri)
headers.each { |key, value| request[key] = value }
request['Content-Type'] = 'application/json'
request.body = JSON.generate(prefix: path, limit: limit, offset: offset,
sortBy: { column: 'name', order: 'asc' })
response = make_request(uri, request)
JSON.parse(response.body)
rescue StandardError => e
{ 'error' => e.message }
end
# Return true only when the API confirms deletion of the requested file
def delete_file(bucket_name, file_path)
uri = URI("#{@storage_url}/object/#{encode_segment(bucket_name)}")
request = Net::HTTP::Delete.new(uri)
headers.each { |key, value| request[key] = value }
request['Content-Type'] = 'application/json'
request.body = JSON.generate(prefixes: [file_path])
response = make_request(uri, request)
deleted = JSON.parse(response.body)
deleted.is_a?(Array) && deleted.any? { |object| object.is_a?(Hash) && object['name'] == file_path }
rescue StandardError
false
end
end
Anwendungsbeispiele
Ein leeres Löschergebnis ist keine Bestätigung: Die Datei kann fehlen oder unter den Storage-Policies des Aufrufers nicht zugänglich sein. Der Helper meldet nur dann Erfolg, wenn die Antwort die angeforderte Datei auflistet.
Nachfolgend finden Sie ein Beispiel dafür, wie Sie mit der Klasse SupabaseStorage Dateien hochladen,
auflisten und aus einem Supabase-Bucket löschen.
# Initialize the client with your environment variables
storage = SupabaseStorage.new(
ENV.fetch('SUPABASE_URL'),
ENV.fetch('SUPABASE_PROJECT_KEY'),
ENV.fetch('SUPABASE_ACCESS_TOKEN')
)
# Upload a file
result = storage.upload_file(
'my-bucket',
'path/to/local/image.jpg',
'uploads/image.jpg'
)
if result['error']
puts "Upload failed: #{result['error']}"
else
puts 'File uploaded successfully'
end
# List files in a bucket
files = storage.list_files('my-bucket', 'uploads/')
if files.is_a?(Array)
files.each do |file|
puts "File: #{file['name']}, Size: #{file.dig('metadata', 'size')}"
end
else
puts "Error listing files: #{files['error']}"
end
# Delete a file
if storage.delete_file('my-bucket', 'uploads/image.jpg')
puts 'File deleted successfully'
else
puts 'Failed to delete file'
end
list_files gibt eine Seite mit den direkten untergeordneten Einträgen zurück, einschließlich
Ordnerzeilen. Wenn Sie mehr als 100 Einträge benötigen, erhöhen Sie offset jeweils um die
Seitengröße, bis eine kürzere Seite zurückgegeben wird. Dieses Beispiel listet Unterordner nicht
rekursiv auf. Uploads erzeugen neue Objekte; bestehende Pfade erfordern einen bewussten Upsert und
die entsprechenden Berechtigungen zum Aktualisieren.
Fehlerbehandlung und Dateivalidierung
Es ist wichtig, Dateien vor dem Upload zu validieren, um Fehler zu vermeiden und die Sicherheit zu gewährleisten. Der folgende Validator prüft auf reguläre Dateien, ein anwendungsspezifisches Größenlimit und zulässige Dateiendungen. Abfragen der Dateiendung und der MIME-Registry prüfen nicht den Inhalt und belegen nicht, dass er sicher ist.
class FileValidator
MAX_FILE_SIZE = 50 * 1024 * 1024 # 50MB
ALLOWED_TYPES = %w[.jpg .jpeg .png .pdf .doc .docx]
def self.validate!(file_path)
raise 'File not found' unless File.file?(file_path)
size = File.size(file_path)
raise 'File exceeds maximum size' if size > MAX_FILE_SIZE
extension = File.extname(file_path).downcase
raise 'Invalid file type' unless ALLOWED_TYPES.include?(extension)
true
end
end
# Example usage:
begin
FileValidator.validate!('path/to/file.jpg')
result = storage.upload_file('my-bucket', 'path/to/file.jpg', 'uploads/file.jpg')
raise result['error'] if result['error']
rescue StandardError => e
puts "Validation failed: #{e.message}"
end
Bewährte Verfahren
Eindeutige Dateinamen erzeugen
Eindeutige Dateinamen helfen dabei, Kollisionen im Speicher zu vermeiden. Zum Beispiel:
require 'securerandom'
def generate_unique_filename(original_filename)
extension = File.extname(original_filename)
basename = File.basename(original_filename, extension)
timestamp = Time.now.strftime('%Y%m%d-%H%M%S')
"#{basename}-#{timestamp}-#{SecureRandom.hex(4)}#{extension}"
end
Dateien nach Datum organisieren
Das Speichern von Dateien in datumsbasierten Verzeichnissen kann die Verwaltung vereinfachen:
def generate_storage_path(filename)
date = Time.now
"uploads/#{date.year}/#{date.month}/#{filename}"
end
Umgang mit großen Dateien
Der obige Client streamt einen Standard-Upload, kann eine unterbrochene Anfrage aber nicht
fortsetzen. Supabase unterstützt fortsetzbare Uploads mit tus
unter /storage/v1/upload/resumable. Verwenden Sie für dieses Protokoll einen kompatiblen tus-Client, anstatt
unabhängige Chunks an den Standard-Objekt-Endpunkt zu senden. Prüfen Sie die im Projekt
konfigurierten Dateigrößenlimits, bevor Sie große Dateien übertragen.
Häufige Anwendungsfälle
- Uploads von Benutzer-Avataren
- Systeme zur Dokumentenspeicherung
- Verwaltung von Mediendateien
- Backup-Lösungen
- Systeme zur Content-Auslieferung
Sicherheitsaspekte
- Validieren Sie Dateien vor dem Upload, um Probleme zu vermeiden.
- Speichern Sie die URL Ihres Supabase-Projekts und Ihren API-Schlüssel in Umgebungsvariablen.
- Implementieren Sie geeignete CORS-Richtlinien, wenn Sie Ihre API öffentlich zugänglich machen.
- Legen Sie geeignete Bucket-Berechtigungen fest.
- Verwenden Sie sichere URLs für sensible Inhalte.
Fazit
Mit Net::HTTP aus Ruby und der Supabase REST API steht Ihnen eine Methode zur Verwaltung von Dateispeicher zur Verfügung. Mit geeigneter Validierung, Fehlerbehandlung und Sicherheitsmaßnahmen können Sie Dateien in Ihren Ruby-Anwendungen effizient in Supabase-Storage-Buckets exportieren.
Für weitere Anforderungen an die Medienverarbeitung können Sie die Funktionen von Transloadit erkunden, um Ihren Workflow weiter zu verbessern.
