Handle creating resources that depend on other resources to exist first?

This title is terrible but I’m having a hard time thinking of a better way to describe what I’m working on.

So I’m working on an app where I have Post Observation and ObservationImage. My schema is like so: Post has_any Observations && Observation has_many ObservationImages.

The way the post creation flow is structured via the design means that the user will be creating an ObservationImage before the observation has been created API side. An observation image essentially just holds some data (%{public_id, :url, :secure_url, :observation_id}) for an image hosted on Cloudinary. I have my separate methods all setup and tested via a Media context that handles validating the params and actually performing the upload and storing the response from Cloudinary.

I have the post/observation flow working right now sans the images by sending my API an observation nested in a post and letting cast_assoc(:observations) in Post do its thing, but the whole image thing is throwing a wrench into the mix.

My question is:

Since I require that an ObservationImage be assigned an Observation on create, how would you approach making sure that an Observation exists first? I thought about via my SPA, when entering the post/observation flow, sending a request to create an empty draft of sorts so that I have at least a post an observation with IDs to work with. Is there a better/different way of handling this? Has anyone used this empty draft approach in the past and run into any edge cases?

I think I could also have a function in the ObservationImage schema file that actually uploads the image after validate_required instead of handling that in a context method. That would allow me to use cast_assoc(:observation_images) in Observation and I wouldn’t need an empty draft at all, but that doesn’t feel quite right.

This sounds like a case for Ecto.Multi to me. This blog seems similar to your use case on a quick skim. Using Ecto Multi For Complex Database Transactions

1 Like

Yeah, I could have used Ecto.Multi for sure!

What I opted for was setting up direct to S3 uploads to a bucket specifically for temporary files. I store the URL of that uploaded file in a nested images array like Post.observations[0].images[0].url. Then, once the user completes the post form and saves it, Ecto handles building out all 3 items, the Post, Observation, and ObservationImage via cast_assoc. It works like a charm! From there, once everything is saved and valid I just copy the file from the temp S3 bucket to the \ bucket for permanent files.

Glad you worked it out :slight_smile:

1 Like