Exporting files to Dropbox in Ruby using the Dropbox SDK
Integrating Dropbox file exports into your Ruby applications can streamline your workflow and
enhance functionality. Dropbox publishes no official Ruby SDK, so this guide uses the
community-maintained dropbox_api gem to automate file
uploads with practical examples.
Prerequisites
Before you begin, ensure you have:
- Ruby 2.7 or higher (tested up to Ruby 3.2)
- Bundler 2.0 or higher
- A Dropbox account
- Basic knowledge of Ruby programming
- SSL support in your development environment
Setting up a Dropbox app and obtaining access tokens
To interact with the Dropbox API, you need to create a Dropbox app and generate an access token:
-
Create a Dropbox App:
- Log in to the Dropbox App Console.
- Click Create app.
- Choose Scoped access and select Full Dropbox or App folder, depending on your needs.
- Give your app a unique name and click Create app.
-
Generate an Access Token:
- In your app's settings, navigate to the OAuth 2 section.
- Under Generated access token, click Generate.
- Copy the generated access token; you will use it in your application.
- Note: since 2021 these console-generated tokens are short-lived and expire after roughly four hours, so they are only useful while you are experimenting. For anything you run more than once, implement the full OAuth2 flow and keep a refresh token instead.
Installing the Dropbox SDK for Ruby
This guide uses the community-maintained dropbox_api gem, version 0.1.21, which is the latest
stable release. Add the gem to your Gemfile:
source 'https://rubygems.org'
gem 'dropbox_api', '~> 0.1.21'
Then install it using Bundler:
bundle install
Authenticating with Dropbox in Ruby
DropboxApi::Client.new only builds a connection object, so it succeeds even when the token is
wrong. Make one cheap API call to find out whether the credentials actually work:
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'))
Uploading files to Dropbox using Ruby
Client#upload posts to /2/files/upload, which takes the file contents as a string and refuses
anything larger than 150 MB. As a conservative policy, this example uses an upload session at or
above that ceiling. Client#upload_by_chunks wraps upload sessions and accepts an open IO handle:
# /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
Note that the single-request branch reads the whole file into memory. Keep an eye on that if you
export many files concurrently, and lower MAX_SINGLE_REQUEST_UPLOAD if your workers are
memory-constrained: upload_by_chunks streams from the handle instead.
Handling errors and exceptions
Rate limiting is the one failure worth retrying automatically, and the gem already models it:
DropboxApi::Errors::TooManyRequestsError carries Dropbox's own retry_after hint. Rescue that
type rather than matching on message text, and let every other error reach the caller so a failed
export is never reported as a success:
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 descends from BasicError, so if you add a rescue DropboxApi::Errors::BasicError branch, put it after this one. Otherwise the broader rescue wins
and the backoff never runs.
Automating file exports in your Ruby application
Automate file exports by processing an entire directory:
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 deliberately stops at the first file it cannot upload, so a partially exported
directory surfaces as an exception instead of a silent success. If you would rather export
everything you can and report the rest, collect the failures per file and raise once at the end.
One thing to plan for before you schedule this: Client#upload defaults to mode: :add with
autorename: false, so a second run over the same directory raises a
DropboxApi::Errors::FileConflictError on the first file that is already there. That default is the
safe one, because it never destroys a remote file. Decide explicitly what you want instead:
- Pass
autorename: trueto keep both copies, and Dropbox appends a counter to the new name. - Pass
mode: :overwriteto replace the remote file. This discards whatever was there, so only choose it when this exporter is the sole writer of that folder. - Or keep the default and track exported filenames locally, so re-runs skip what already landed.
Rails integration considerations
If you integrate Dropbox exports within a Rails application, be mindful of thread safety and process forking issues. Ensure that any background jobs or scheduled tasks are configured using thread-safe patterns and robust scheduling libraries to prevent concurrency conflicts, especially in production environments.
Conclusion
Integrating the Dropbox SDK into your Ruby application can automate file exports and streamline your workflow. This guide provided a step-by-step approach covering authentication, file uploading, error handling with retry logic, and directory processing. For robust file handling and processing capabilities, you might also consider exploring Transloadit's services.
