Managing avatars on Bubble.io with Supabase

Image without caption
This recipe outlines the process of creating a dedicated bucket in Supabase for avatar storage, securing the bucket, automating profile updates upon avatar picture upload and deletion, and implementing avatar management in your Bubble.io app.
It is specifically designed to work with the Supabase plugin, available here.

1. Prerequisites

This guide is the next step following our previous guide on designing and automating profile creation upon user signup, which you can retrieve here.
We assume that you have created a profiles table in the public schema structured as follows:
sql
CREATE TABLE public.profiles ( id uuid not null references auth.users on delete cascade, first_name text, last_name text, bio text, avatar text, primary key (id) );

2. Creating a bucket for avatars storage

We will create a dedicated bucket in Supabase specifically for storing user avatars.
Each user will be assigned a unique folder, with the folder names based on the UUID of the user to ensure a clear structure. Within each user's folder, the avatar image will be named avatar.png.
Let's start by creating a private bucket called avatars. We allow only PNG files to be uploaded to this bucket.
Create avatars bucket

3. Set up Row-Level Security (RLS) policies

Now, we'll implement Row Level Security (RLS) in Supabase for the avatars bucket, allowing users to manage their own avatars.
To implement our RLS policies for avatar management, we leverage the user ID (UUID) as folder names. Our policies specifically check the folder name against the authenticated user's ID, allowing users to access and update only their respective avatar folders.
You can use the SQL editor in the Supabase dashboard to implement these policies.

Allow upload
sql
CREATE POLICY "Allow users to insert their avatar" ON storage.objects FOR INSERT TO authenticated WITH CHECK ( bucket_id = 'avatars' AND (storage.foldername(name))[1] = auth.uid()::text );
This policy allows authenticated users to insert their avatar within their own folder in the avatars bucket.

Allow update
sql
create policy "Allow users to update their own avatar" on storage.objects for update to authenticated using ( bucket_id = 'avatars' and (storage.foldername(name))[1] = auth.uid()::text );
This policy allows authenticated users to update only their own avatar within their folder in the avatars bucket.

Allow view
sql
create policy "Allow users to view their own avatar" on storage.objects for select to authenticated using ( bucket_id = 'avatars' and (storage.foldername(name))[1] = auth.uid()::text );
This policy allows authenticated users to view only their own avatar within their folder in the avatars bucket.

Allow delete
sql
create policy "Allow users to delete their own avatar" on storage.objects for delete to authenticated using ( bucket_id = 'avatars' and (storage.foldername(name))[1] = auth.uid()::text );
This policy permits authenticated users to delete only their own avatar within their specific folder in the avatars bucket.

4. Automating profile update upon avatar picture upload

Whenever a user upload a picture on the avatars bucket we want to update the avatar field relative to the user on the profiles table.
To automate that, a PostgreSQL function alongside a database trigger can be used.

Function

The set_avatar_to_user function updates the user's avatar in the profiles table when a new file is uploaded to the avatars bucket, and the folder in which the file is stored matches the user's ID.
sql
CREATE OR REPLACE FUNCTION set_avatar_to_user() RETURNS TRIGGER AS $$ BEGIN IF NEW.bucket_id = 'avatars' AND (storage.foldername(NEW.name))[1] = NEW.owner_id THEN UPDATE profiles SET avatar = NEW.name WHERE id = NEW.owner; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql;

Trigger

The trigger_set_avatar_to_user is invoked after each new file upload to storage.objects and is responsible for calling the set_avatar_to_user function.
sql
CREATE TRIGGER trigger_set_avatar_to_user AFTER INSERT ON storage.objects FOR EACH ROW EXECUTE FUNCTION set_avatar_to_user();
In this setup, the set_avatar_to_user function is responsible for updating user avatars in the public.profiles table. Meanwhile, the trigger_set_avatar_to_user guarantees that this function is automatically called whenever a new file is added to storage.objects, ensuring user profiles are updated with the correct avatars.

5. Allow users to manage their avatar on Bubble.io

Now, we will enable our users to upload their profile pictures and display them in our Bubble.io app.
Avatar management
To implement this, you can follow these steps:
  1. Add an uploader component to your page.
  1. Add a storage component (used for creating a signed URL, as our bucket is private).
  1. Trigger a workflow when a file has been successfully uploaded through the uploader component.
In this workflow, we will:
  • Call the Create Signed URL action, using avatars as the bucket name and the profile avatar field as the path.
  • Call the Reset action from the uploader component.
Uploading avatar
To display the avatar in your app:
  • On page load, call the Create Signed URL action if the avatar field is not empty.
  • Then use the Signed URL field from the storage component as the source for the image.
Please note that in this example, we are displaying a default image if the user has not uploaded their own.