Using model ID for direct S3 upload in 'new' action?

I'm currently uploading directly to S3 in my rails app using jQuery file upload.

I have a pm_report which has 3 photos inside, and I'm uploading them without any problems on already existing reports.

The problem appears when I try to create a new report, because it tries to establish the path for the photos to be uploaded to before saving the report to the database (it has no id yet).

What I have:

pm_reports_controller.rb

...
before_action :set_s3_direct_post, only: [:new, :edit, :create, :update]
...
private
...
  def set_s3_direct_post
      @s3_direct_post = S3_BUCKET.presigned_post(key: "pm_reports/#{@pm_report.id}/${filename}", success_action_status: '201', acl: 'private')
  end

What I want to accomplish: Save the 3 images of the report on its own folder inside pm_reports on S3.

Is there a way I can implement a workaround for this issue, or maybe a different approach?

Answers


EDIT: Found a better solution.

The logic goes as this.

Create a second bucket for your app, set a rule to auto-delete in x days. Upload directly using jQuery file upload to the S3 temporary bucket. Then add an after_commit callback in the model so you can change the temporary upload path to it's final path by copying the object from one bucket to another using aws-sdk gem.

That let me add a fixed name for the object since it suits my problem, so, after making the callback, I set the final path and then just display it on an image_tag on the view.

Will elaborate and put some code if someones asks me to.



I used an uuid as a different approach like Brent pointed out in his comment.

I had to change a few things:

Add a migration

class AddUuidToPmReports < ActiveRecord::Migration
   def change
     add_column :pm_reports, :uuid, :uuid
   end
end

Change pm_reports_controller.rb so it sets the s3 direct post after the 'new' action and before the 'edit' action. Also, change the key of the presigned post to use the uuid and accept it in as a strong parameter.

...
before_action :set_s3_direct_post, only: :edit
...
def new
    @pm_report = PmReport.new
    @pm_report.uuid = SecureRandom.uuid
    set_s3_direct_post
end
...
private
...
def pm_report_params
      params.require(:pm_report).permit( ..., :uuid)
    end

  def set_s3_direct_post
      @s3_direct_post = S3_BUCKET.presigned_post(key: "pm_reports/#{@pm_report.uuid}/${filename}", success_action_status: '201', acl: 'private')
  end

And lastly, add a hidden field for the uuid to be passed with the form so we can save it.

view/pm_reports/_form.html.erb

<%= form_for @pm_report, ... %>
...
<%= f.hidden_field(:uuid) %>
...
<%= f.submit %>

Need Your Help

LINQ to Entities group-by failure using .date

c# linq linq-to-entities entity-framework-4 group-by

I am trying to do a Linq group by on just the date part of a datetime field.

Interbase how to add guid field to existing table

sql interbase

I have an old existing interbase table and I want to add a primary key field to and populate it. Is there any way to do it all in the SQL statement (like SQL server). Example: