Last updated: February 5, 2025

<span aria-hidden="true" id="exporting-files-to-supabase-buckets-in-ruby"></span>

# Exporting files to Supabase Buckets in Ruby

![Tim Koschützki](/assets/images/teammates/avatar-tim-kos-1.jpg?dpl=dpl_6nhQNS5wkVkPZWuKMzXcWrAHNJL5)

**Tim Koschützki**

Co-founder · Berlin, Germany · Show bio

[](https://x.com/tim%5Fkos)[](https://github.com/tim-kos)

Supabase offers a robust cloud storage solution through its bucket system. Although the official Ruby SDK for Supabase is under active development and does not yet support storage operations, you can interact with Supabase Storage using Ruby's built-in HTTP libraries. In this guide, we illustrate how to export files to Supabase storage buckets via the REST API.

<span aria-hidden="true" id="prerequisites"></span>

## Prerequisites

Before beginning, ensure you have:

* Ruby 2.7 or higher installed
* A Supabase account and project with storage enabled
* Basic familiarity with Ruby programming
* Your Supabase project URL and API key

<span aria-hidden="true" id="setting-up-your-environment"></span>

## Setting up your environment

Create a new Ruby project and set up the necessary dependencies. Although some libraries like`net/http` and `json` come with Ruby, we include them for clarity, and add `mime-types` for determining file content types:

```bash
mkdir supabase-storage-demo
cd supabase-storage-demo
bundle init

```

Add the following gems to your Gemfile:

```ruby
source 'https://rubygems.org'

# Net/http and JSON are part of Ruby's standard library
gem 'mime-types'

```

Install the dependencies:

```bash
bundle install

```

<span aria-hidden="true" id="configuring-a-rest-api-client-in-ruby"></span>

## Configuring a REST API client in Ruby

Since direct storage operations via a Ruby SDK are not available, we'll build a simple client using Ruby's Net::HTTP to interact with the Supabase Storage REST API.

```ruby
require 'net/http'
require 'json'
require 'mime/types'

class SupabaseStorage
  def initialize(project_url, api_key)
    @project_url = project_url.chomp('/')
    @api_key = api_key
    @storage_url = "#{@project_url}/storage/v1"
  end

  private

  def headers
    {
      'Authorization' => "Bearer #{@api_key}",
      'apikey' => @api_key
    }
  end

  def make_request(uri, request)
    Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
      http.request(request)
    end
  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/#{bucket_name}/#{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
      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 files in a bucket with an optional prefix path
  def list_files(bucket_name, path = '')
    uri = URI("#{@storage_url}/object/list/#{bucket_name}")
    uri.query = URI.encode_www_form(prefix: path)

    request = Net::HTTP::Get.new(uri)
    headers.each { |key, value| request[key] = value }

    response = make_request(uri, request)
    JSON.parse(response.body)
  rescue StandardError => e
    { 'error' => e.message }
  end

  # Delete a file from a bucket; returns true if deletion is successful
  def delete_file(bucket_name, file_path)
    uri = URI("#{@storage_url}/object/#{bucket_name}/#{file_path}")

    request = Net::HTTP::Delete.new(uri)
    headers.each { |key, value| request[key] = value }

    response = make_request(uri, request)
    response.code == '200' || response.code == '204'
  rescue StandardError => e
    false
  end
end

```

<span aria-hidden="true" id="usage-examples"></span>

## Usage examples

Below is an example of how to use the `SupabaseStorage` class to upload, list, and delete files from a Supabase bucket.

```ruby
# Initialize the client with your environment variables
storage = SupabaseStorage.new(
  ENV['SUPABASE_URL'],
  ENV['SUPABASE_ANON_KEY']
)

# 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

```

<span aria-hidden="true" id="error-handling-and-file-validation"></span>

## Error handling and file validation

It is important to validate files before uploading to avoid errors and ensure security. The following validator checks for file existence, size limits, and allowed file types.

```ruby
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.exist?(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')
  storage.upload_file('my-bucket', 'path/to/file.jpg', 'uploads/file.jpg')
rescue StandardError => e
  puts "Validation failed: #{e.message}"
end

```

<span aria-hidden="true" id="best-practices"></span>

## Best practices

<span aria-hidden="true" id="generate-unique-filenames"></span>

### Generate unique filenames

Creating unique filenames helps prevent collisions in storage. For example:

```ruby
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

```

<span aria-hidden="true" id="organize-files-by-date"></span>

### Organize files by date

Storing files in date-based directories can simplify management:

```ruby
def generate_storage_path(filename)
  date = Time.now
  "uploads/#{date.year}/#{date.month}/#{filename}"
end

```

<span aria-hidden="true" id="handling-large-files"></span>

### Handling large files

Supabase Storage's REST API does not currently support native chunked uploads. For large file uploads, you might need to implement custom logic by splitting your file into smaller chunks and uploading them sequentially or using an intermediary server solution.

```ruby
def upload_large_file(bucket_name, file_path, destination_path, chunk_size = 5_242_880)
  File.open(file_path, 'rb') do |file|
    while (chunk = file.read(chunk_size))
      # Implement your custom chunked upload logic here.
      # This may involve storing chunks temporarily and then finalizing the upload.
      puts "Uploading chunk of size #{chunk.size} bytes..."
      # For demonstration, we simply note the chunk size.
    end
  end
end

```

<span aria-hidden="true" id="common-use-cases"></span>

## Common use cases

* User avatar uploads
* Document storage systems
* Media file management
* Backup solutions
* Content delivery systems

<span aria-hidden="true" id="security-considerations"></span>

## Security considerations

* Validate files before uploading to prevent issues.
* Store your Supabase project URL and API key in environment variables.
* Implement proper CORS policies if exposing your API.
* Set appropriate bucket permissions.
* Use secure URLs for sensitive content.

<span aria-hidden="true" id="conclusion"></span>

## Conclusion

While the official Ruby SDK for Supabase remains under active development, using Ruby's Net::HTTP and the Supabase REST API provides a viable method for managing file storage. With proper validation, error handling, and security measures, you can efficiently export files to Supabase storage buckets in your Ruby applications.

For additional media processing needs, consider exploring Transloadit's features to further enhance your workflow.

\#supabase#ruby#file-exporting-service

### 👩‍💻 Join 20k+ developers

Sign up for our [monthly newsletter](/newsletters.md) to receive direct links to 3 exclusive tech — and 2 product updates. No less, no more.

Your email:

Get access

## File uploading and encoding. Made simple.

Transloadit streamlines file handling for developers, trusted by brands like Coursera and The New York Times. We’re known for a reliable API, top-notch support, and a strong commitment to open source, with projects like [Uppy⁠](https://uppy.io) and [Tus⁠](https://tus.io) setting standards in file processing.

[Sign up](/c/)[Book a Demo](https://survey.typeform.com/to/kRg47Xi5)

No credit card needed · 5 GB included in the free plan

Cancel anytime
