mardi 9 novembre 2021

Presigned url upload and linking using active storage

I'm trying to upload attachments via AWS s3 presigned url. It is done as a 2 step process . First I created an API for generating a presigned post url and sent to client React App.

class Admin::PresignedUploadController < ApplicationController
  before_action :authenticate_user!, only: [:index]
  before_action :load_aws_credentials, only: [:index]
  before_action :load_bucket, only: [:index]

  def index
    presigned_url = @s3_bucket.presigned_post(
      key: "#{Rails.env}/#{SecureRandom.uuid}/${filename}",
      success_action_status: "201",
      signature_expiration: (Time.zone.now.utc + 15.minutes)
    )

    data = { url: presigned_url.url, url_fields: presigned_url.fields }

    render json: data, status: :ok
  end

  private

    def load_bucket
      @s3_bucket = Aws::S3::Resource.new(
        region: ENV["AWS_REGION"],
        credentials: @aws_credentials
      ).bucket(ENV["AWS_BUCKET_NAME"])
    end

    def load_aws_credentials
      @aws_credentials = Aws::Credentials.new(
        ENV["AWS_ACCESS_KEY_ID"],
        ENV["AWS_SECRET_ACCESS_KEY"]
        )
    end
end

I'm able to upload the file via a post request to the url and get a response from s3.

<PostResponse>
    <Location>https://neeto-chat-staging-v1.s3.amazonaws.com/development%2Fa185e6a8-b4eb-402e-a11a-a2c8ed48bdea%2Fwallpaper-photos-3.jpg</Location>
    <Bucket>neeto-chat-staging-v1</Bucket>
    <Key>development/a185e6a8-b4eb-402e-a11a-a2c8ed48bdea/wallpaper-photos-3.jpg</Key>
    <ETag>"2cbc861b2a9e0c48c7a7edf565f6a509"</ETag>
</PostResponse>

My first problem is that the Location is not accessible and it is showing access denied. I hope it might get solved after giving GET permission in AWS s3.

Is the Location returning the public url of the file?

Do I have to make an additional request to attach it to the model using active record or can it be done automatically using active record?

My schema for attachments:

  create_table "active_storage_attachments", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
    t.string "name", null: false
    t.string "record_type", null: false
    t.uuid "record_id", null: false
    t.uuid "blob_id", null: false
    t.datetime "created_at", null: false
    t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
    t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness",
unique: true
  end

My model Message has:

 has_many_attached :attachments

 def get_url(attachment)
      Rails.application.routes.url_helpers.rails_blob_path(
        attachment, only_path: true
      )
    end

def get_attachments
  if attachments.attached?
    self.attachments.attachments.map do |attachment|
      {
        filename: attachment.filename,
        url: get_url(attachment),
        id: attachment.id
      }
    end
  end
end

Aucun commentaire:

Enregistrer un commentaire