Shrine: S3 URL/local URL default_url

Created on 9 Apr 2019  路  8Comments  路  Source: shrinerb/shrine

  • Issues are for bug reports only.

    - Have a question or unsure if it's a bug, then please inquire on the ruby-shrine Google Group.

Brief Description

When one instance doesn't have an image, it should return the default_url, however this one doesn't have correct host.

Expected behavior

If i call user.avatar_url(:thumbnail), and the user doesn't have an avatar, it should return the absolute path to the image: https://localhost:port/assets/users/defaults/avatar.png

Actual behavior

Shrine only returns the relative path: /assets/users/defaults/avatar.png

Simplest self-contained example code to demonstrate issue

The ImageUploader I'm currently using looks like this:

  Attacher.default_url do |_options|
    class_name = context[:record].class.name.to_s.downcase
    "/assets/defaults/#{class_name}/#{context[:name]}.png" # => /assets/defaults/user/avatar.png
  end

Right now I'm forcing the storages to be used as S3, since I want to test the production environment locally with my docker machine:

  require "shrine/storage/s3"

  s3_options = {
    bucket:            ENV["AWS_BUCKET_NAME"],
    region:            ENV["AWS_REGION"],
    access_key_id:     ENV["AWS_ACCESS_KEY_ID"],
    secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
  }

  Shrine.storages = {
    cache: Shrine::Storage::S3.new(prefix: "#{ENV['AWS_WEBAPP_FOLDER']}_cache", **s3_options),
    store: Shrine::Storage::S3.new(prefix: ENV['AWS_WEBAPP_FOLDER'], **s3_options),
  }

My question is:

  1. My rails app is only an API app, so it's using the port 5000, and my actual frontend app is using port 3000. How can I get default_url to be localhost:5000/assets/... and non-default_url to be actual S3 images (S3 images are working correctly)
  2. Am I misunderstanding how default_url works? Should I manually upload the default_urls to S3? How would this work in a production environment? Since my frontend app doesn't have the same assets, a path like assets/images/defaults/avatar.png will just return 404, since the image itself is in the rails server, and not in the frontend app.

System configuration

Ruby version: 2.6.2

Shrine version: 2.16.0

All 8 comments

Yes, Shrine doesn't know about request context, so what you return in the default_url block is what the resulting URL would be.

Doesn't Rails have some method where you could give it a path, and it would return a URL with added host and port matching your Rails app? Maybe #url_for can do that; if it receives a full S3 URL, then it doesn't do anything, but if it receives only a path, then it adds the scheme & host & port of the Rails app?

Do you think there is something we can change in Shrine to make this easier? (besides adding a Rails integration which I'm against)

Janko,

thanks for your answer.

My initial thought when I started using shrine, was that there should be some kind of option to either:

  1. Set the default_url host
  2. Have some kind of boolean option to determine whether the default_url is is absolute or relative.

In short, I think the default_url plugin could be more customizable. Please tell me if this makes sense to you, or if you think this shouldn't be the responsibility of Shrine itself. I'm coming from Paperclip so I'm a little bit used to working with absolute URLs (including host). To me it made sense that the "image handler library" took care of "everything regarding images", so giving the responsibility to some kind of rails wrapper doesn't seem quite right to me.

Let me know what you think.

Thanks.

Yes, I agree, and want to make default_url plugin more customizable if possible. Could you give me an example of how you imagine the API to look like? I just want to see if I understand it correctly.

The 1.) and 2.) you mentioned would be a plugin-level option? Something like this?

plugin :default_url, host: "http://localhost:5000"

Or do you want to be able to pass :host when generating the URL? That probably wouldn't be possible, as in case the attachment _is_ present, the :host option would be forwarded to the S3 storage, which is not what you want.

Janko,

correct, that's just what I meant. The idea behind this would be to "standardize" the default_url plugin to only work with absolute paths. I imagine that I would be using an ENV variable for this, like:

plugin :default_url, host: ENV['IMAGE_HOST'] 

Actually, if you take a look at development.rb in a rails project, you will see that there's something very similar available:

routes.default_url_options[:host] = 'localhost:5000'

We would be basically reproducing this same behaviour, but without the need to do a "full rails integration".

Sounds good, I'll add that option.

Awesome, let me know if I can be of any help. Will be glad to test it out.

@waclock Let me know whether this works for you, I'll be releasing a new version soon.

Hello @janko. Sorry for taking so long to respond.

Yes, this looks perfect and it follows the rails standard for host URL generation.

Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

musaffa picture musaffa  路  7Comments

pmackay picture pmackay  路  4Comments

nynhex picture nynhex  路  6Comments

jakehockey10 picture jakehockey10  路  6Comments

Grafikart picture Grafikart  路  4Comments