Dateien mit dem Dropbox SDK in Ruby nach Dropbox exportieren
Die Integration von Dropbox-Datei-Exporten in Ihre Ruby-Anwendungen kann Ihre Abläufe straffen und
den Funktionsumfang erweitern. Dropbox veröffentlicht kein offizielles Ruby SDK, daher verwendet
dieser Leitfaden das von der Community gepflegte Gem dropbox_api,
um Datei-Uploads anhand praxisnaher Beispiele zu automatisieren.
Voraussetzungen
Bevor Sie beginnen, stellen Sie sicher, dass Sie über Folgendes verfügen:
- Ruby 2.7 oder höher (getestet bis Ruby 3.2)
- Bundler 2.0 oder höher
- Ein Dropbox-Konto
- Grundkenntnisse in der Ruby-Programmierung
- SSL-Unterstützung in Ihrer Entwicklungsumgebung
Eine Dropbox-App einrichten und Zugriffstoken erhalten
Um mit der Dropbox-API zu interagieren, müssen Sie eine Dropbox-App erstellen und ein Zugriffstoken generieren:
-
Erstellen Sie eine Dropbox-App:
- Melden Sie sich in der Dropbox App Console an.
- Klicken Sie auf Create app.
- Wählen Sie Scoped access und anschließend Full Dropbox oder App folder, je nach Ihren Anforderungen.
- Geben Sie Ihrer App einen eindeutigen Namen und klicken Sie auf Create app.
-
Generieren Sie ein Zugriffstoken:
- Navigieren Sie in den Einstellungen Ihrer App zum Abschnitt OAuth 2.
- Klicken Sie unter Generated access token auf Generate.
- Kopieren Sie das generierte Zugriffstoken; Sie verwenden es in Ihrer Anwendung.
- Hinweis: Seit 2021 sind diese in der Console generierten Token kurzlebig und laufen nach etwa vier Stunden ab, sodass sie nur zum Experimentieren taugen. Implementieren Sie für alles, was Sie mehr als einmal ausführen, den vollständigen OAuth2-Flow und arbeiten Sie stattdessen mit einem Refresh Token.
Das Dropbox SDK für Ruby installieren
Dieser Leitfaden verwendet das von der Community gepflegte Gem dropbox_api in Version 0.1.21,
dem aktuellen stabilen Release. Fügen Sie das Gem Ihrem Gemfile hinzu:
source 'https://rubygems.org'
gem 'dropbox_api', '~> 0.1.21'
Installieren Sie es anschließend mit Bundler:
bundle install
In Ruby bei Dropbox authentifizieren
DropboxApi::Client.new erstellt lediglich ein Verbindungsobjekt und ist daher auch dann
erfolgreich, wenn das Token falsch ist. Setzen Sie einen einzigen ressourcenschonenden API-Aufruf
ab, um herauszufinden, ob die Zugangsdaten tatsächlich funktionieren:
require 'dropbox_api'
def initialize_dropbox_client(access_token)
client = DropboxApi::Client.new(access_token)
# The constructor never talks to Dropbox; this call is what validates the token.
client.get_current_account
client
rescue DropboxApi::Errors::HttpError
# HttpError#message is built as "HTTP <status>: <body>", so it carries Dropbox's raw response.
# Log the type, and keep the body for a debug sink rather than standard output.
puts 'Could not reach Dropbox: the API returned an unexpected HTTP response'
raise
rescue DropboxApi::Errors::BasicError => e
puts "Dropbox rejected the access token: #{e.class}"
raise
end
# Initialize the client
dbx = initialize_dropbox_client(ENV.fetch('DROPBOX_ACCESS_TOKEN'))
Dateien mit Ruby zu Dropbox hochladen
Client#upload sendet an /2/files/upload, das den Dateiinhalt als String entgegennimmt und alles
ablehnt, was größer als 150 MB ist. Als konservative Vorgehensweise verwendet dieses Beispiel ab
dieser Obergrenze eine Upload-Session. Client#upload_by_chunks kapselt Upload-Sessions und akzeptiert ein offenes Handle vom Typ IO:
# /2/files/upload rejects payloads above 150 MB. Dropbox does not say whether it counts decimal
# or binary megabytes, and an upload session accepts any size, so switch over at the lower reading.
MAX_SINGLE_REQUEST_UPLOAD = 150 * 1000 * 1000
def upload_file(client, file_path, dropbox_path)
if File.size(file_path) >= MAX_SINGLE_REQUEST_UPLOAD
File.open(file_path, 'rb') do |file|
client.upload_by_chunks(dropbox_path, file)
end
else
client.upload(dropbox_path, File.binread(file_path))
end
puts "File '#{file_path}' uploaded to '#{dropbox_path}'"
end
# Usage example
begin
local_file = 'path/to/your/local/file.txt'
dropbox_destination = '/Apps/YourAppFolder/file.txt'
upload_file(dbx, local_file, dropbox_destination)
rescue DropboxApi::Errors::BasicError, SystemCallError => e
puts "Failed to upload file: #{e.message}"
rescue DropboxApi::Errors::HttpError => e
# Again: no raw response body on standard output.
puts "Failed to upload file: #{e.class}"
end
Beachten Sie, dass der Zweig mit der einzelnen Anfrage die gesamte Datei in den Arbeitsspeicher
lädt. Behalten Sie das im Blick, wenn Sie viele Dateien gleichzeitig exportieren, und verringern Sie
MAX_SINGLE_REQUEST_UPLOAD, wenn Ihre Worker wenig Arbeitsspeicher haben:
upload_by_chunks streamt stattdessen aus dem Handle.
Fehler und Ausnahmen behandeln
Rate Limiting ist der einzige Fehlerfall, bei dem sich ein automatischer erneuter Versuch lohnt, und
das Gem bildet ihn bereits ab: DropboxApi::Errors::TooManyRequestsError enthält den Hinweis retry_after, den Dropbox selbst
liefert. Fangen Sie diesen Typ ab, statt auf den Meldungstext zu prüfen, und lassen Sie jeden
anderen Fehler bis zum Aufrufer durch, damit ein fehlgeschlagener Export nie als Erfolg gemeldet
wird:
def handle_upload_with_retry(client, file_path, dropbox_path, max_retries = 3)
retries = 0
begin
upload_file(client, file_path, dropbox_path)
rescue DropboxApi::Errors::TooManyRequestsError => e
raise if retries >= max_retries
retries += 1
# The gem sets retry_after from `headers['retry-after'].to_i`, so a response without the header
# arrives as 0, and 0 is truthy in Ruby. Test for a positive value, or the backoff never runs.
wait = e.retry_after.to_i.positive? ? e.retry_after.to_i : 2**retries
puts "Rate limited, retrying '#{file_path}' in #{wait}s (attempt #{retries}/#{max_retries})"
sleep(wait)
retry
end
end
TooManyRequestsError erbt von BasicError. Wenn Sie also einen Zweig für rescue DropboxApi::Errors::BasicError ergänzen, platzieren Sie ihn nach diesem Zweig. Andernfalls greift
das allgemeinere rescue und das Backoff wird nie ausgeführt.
Datei-Exporte in Ihrer Ruby-Anwendung automatisieren
Automatisieren Sie Datei-Exporte, indem Sie ein ganzes Verzeichnis verarbeiten:
class DropboxExporter
def initialize(access_token)
@client = initialize_dropbox_client(access_token)
end
def process_directory(local_dir, dropbox_dir)
Dir.glob(File.join(local_dir, '*')).each do |file_path|
next unless File.file?(file_path)
dropbox_path = File.join(dropbox_dir, File.basename(file_path))
handle_upload_with_retry(@client, file_path, dropbox_path)
end
end
end
# Usage example
exporter = DropboxExporter.new(ENV.fetch('DROPBOX_ACCESS_TOKEN'))
exporter.process_directory('local/files', '/Apps/YourAppFolder')
process_directory bricht bewusst bei der ersten Datei ab, die nicht hochgeladen werden kann, sodass ein
nur teilweise exportiertes Verzeichnis als Ausnahme sichtbar wird und nicht als stiller Erfolg. Wenn
Sie lieber alles exportieren möchten, was möglich ist, und den Rest melden, sammeln Sie die Fehler
pro Datei und lösen Sie am Ende einmal eine Ausnahme aus.
Eines sollten Sie einplanen, bevor Sie das zeitgesteuert ausführen: Client#upload verwendet standardmäßig mode: :add mit
autorename: false, sodass ein zweiter Durchlauf über dasselbe Verzeichnis bei der ersten
bereits vorhandenen Datei eine Ausnahme vom Typ DropboxApi::Errors::FileConflictError auslöst. Diese
Standardeinstellung ist die sichere, denn sie zerstört nie eine Datei auf der Remote-Seite.
Entscheiden Sie explizit, was Sie stattdessen möchten:
- Übergeben Sie
autorename: true, um beide Kopien zu behalten; Dropbox hängt dann einen Zähler an den neuen Namen an. - Übergeben Sie
mode: :overwrite, um die Datei auf der Remote-Seite zu ersetzen. Dabei geht verloren, was dort vorhanden war; wählen Sie das also nur, wenn dieser Exporter der einzige Schreiber dieses Ordners ist. - Oder behalten Sie die Standardeinstellung bei und protokollieren Sie die exportierten Dateinamen lokal, damit erneute Durchläufe überspringen, was bereits angekommen ist.
Überlegungen zur Rails-Integration
Wenn Sie Dropbox-Exporte in einer Rails-Anwendung integrieren, achten Sie auf Thread-Sicherheit und auf Probleme beim Forken von Prozessen. Stellen Sie sicher, dass Hintergrund-Jobs und geplante Aufgaben mit thread-sicheren Mustern und robusten Scheduling-Bibliotheken konfiguriert sind, um Nebenläufigkeitskonflikte zu vermeiden, besonders in Produktionsumgebungen.
Fazit
Die Integration des Dropbox SDK in Ihre Ruby-Anwendung kann Datei-Exporte automatisieren und Ihre Abläufe straffen. Dieser Leitfaden hat Schritt für Schritt die Authentifizierung, das Hochladen von Dateien, die Fehlerbehandlung mit Wiederholungslogik und die Verarbeitung von Verzeichnissen behandelt. Für robuste Funktionen zur Dateiverarbeitung können Sie auch einen Blick auf die Dienste von Transloadit werfen.
