3

I am in the process of migrating my Rails app from using PaperClip to ActiveStorage.

In one of my models, I had the following method (using paperclip):

class ECard < ActiveRecord
    def thumb_url
        self.attachment.url(:thumb)
    end
end

And in the controller I have:

def by_type
    @e_cards = ECard.where(type_id: params[:type_id]).as_json(:only => [:id, :name], :methods => [:thumb_url])
    respond_to do |format|
        format.json { render json: @e_cards }
    end   
end

Now, that I am using ActiveStorage, how to I get the thumbnail url of the attachment from the thumb_url method?

Works: Rails.application.routes.url_helpers.rails_blob_path(attachment, only_path: true)

Does not work: Rails.application.routes.url_helpers.rails_blob_path(attachment.variant(resize: '200x200'), only_path: true) This throws the error: NoMethodError (undefined method 'signed_id' for #<ActiveStorage::Variant:0x00007fac1960eab0>)

How do I achieve this?

mridula
  • 3,203
  • 3
  • 32
  • 55

2 Answers2

10

Found it!

def thumb_url 
    Rails.application.routes.url_helpers.rails_representation_url(attachment.variant(resize: "200x200").processed, only_path: true)
end

Found from this answer.

mridula
  • 3,203
  • 3
  • 32
  • 55
  • 2
    This kind of "hack" is a code smell (it's "hard" to do because urls are something more related to views, that does not belong to the models but to the view you are rendering). Instead of using `as_json` you could have a json view. `as_json` is fine on some cases but it feels like sometimes it's cleaner to use a view. – arieljuod Jan 10 '19 at 13:04
  • @arieljuod. Thank you. I had the intuition that since the answer was difficult to find, its probably because the model is supposed to not have anything to do with attachments and URLs. I will modify the code to return json view. – mridula Jan 10 '19 at 13:35
  • @mridula thanks. Do you have a full example of your new solution in a model /controller with `as_json`? What is an `attachment` in your code? Is it the same `def` for multiple files solution? – laimison Aug 05 '19 at 23:40
  • @laimison, sorry! I don't work on that project anymore and I don't recall my solution. – mridula Aug 16 '19 at 16:16
  • @mridula no probs, sorted this in a different way. Actually, I was more interested to see this URL in the controller. Then I can add URL to GET response for the frontend. – laimison Aug 16 '19 at 16:44
  • Adding .processed will check if the variant has been created yet. If not it will fetch the image, process it and save it. If using an external storage like s3 that could be rather slow so be aware of this. If you leave .processed off it will still work and return the url string, and the processing will happen on first request to that url. – Shane E. Oct 16 '20 at 10:58
  • worked like a charm, – DivinesLight Jan 04 '22 at 16:08
0

attachment.variant(resize: "200x200").service.url works for me. It give you the external url while working with S3 and not the internal link for your app.

Juanin
  • 602
  • 1
  • 8
  • 16