anurag
anurag

Reputation: 2246

Rails 5.2 Rest API + Active Storage + React - Add attachment url to controller response

Would want to add the url for the attached file, while responding to get request for a nested resource (say Document) for parent resource (say Person).

# people_controller.rb  
def show
   render json: @person, include: [{document: {include: :files}}]
end


# returns
# {"id":1,"full_name":"James Bond","document":{"id":12,"files":[{"id":12,"name":"files","record_type":"Document","record_id":689,"blob_id":18,}]}


# MODELS
# person.rb  
class Person < ApplicationRecord
   has_one :document, class_name: "Document", foreign_key: :document_id
end

# document.rb
class Document < ApplicationRecord
   has_many_attached :files
end

Issue being, I want to show the file or provide a link to the file in a React frontend setup, which doesn't have helper methods like url_for. As pointed out here.

Any help, would be greatly appreciated.

Upvotes: 5

Views: 5320

Answers (4)

stevec
stevec

Reputation: 52478

All credit to @JuanCarlosGamaRoa for this, which worked for me.

I had a app where each 'product' has one 'main_image' attachment.

# app/models/product.rb
def main_image_url
  if self.main_image.attached?
    Rails.application.routes.url_helpers.rails_blob_path(self.main_image, only_path: true)
  else
    nil
  end
end
# app/views/products/_product.json.jbuilder
json.extract! product, :id, :price, :created_at, :updated_at, :main_image_url
json.url product_url(product, format: :json)

Upvotes: 0

rhd727
rhd727

Reputation: 21

class Meal < ApplicationRecord
  has_many_attached :photos
end  

class MealsController < ApplicationController
  def index
    render json: current_user.meals.map { |meal| meal_json(meal) }
  end

  def show
    render json: meal_json(current_user.meals.find!(params[:id]))
  end

  private

  def meal_json(meal)
    meal.as_json.merge(photos: meal.photos.map { |photo| url_for(photo) })
  end
end

Upvotes: 1

Juan Carlos Gama Roa
Juan Carlos Gama Roa

Reputation: 61

What I have done is create this method in the model

def logo_url
  if self.logo.attached?
    Rails.application.routes.url_helpers.rails_blob_path(self.logo, only_path: true)
  else
    nil
  end
end

To add logo_url to your response json you can add methods.

render json: @person, methods: :logo_url

that is explained in the official guides =)

Upvotes: 6

anurag
anurag

Reputation: 2246

After digging in the source code of Active Storage, I found out model methods which exposed method called: service_url, which returns a short lived link to the attachment files.

Then this answer helped include the method inside the controller response json.

so, in order to achieve my required output I had to do

render json: @person, include: [{document: {include: {files: {include: {attachments: {include: {blob: {methods: :service_url}}}}} }}]

Upvotes: 5

Related Questions