I have a basic ActiveStorage setup with one model that has_many_attached :file_attachments
. In a service elsewhere I'm trying to generate a link to be used outside the main app (email, job etc).
With S3 in production I can do:
item.file_attachments.first.service_url
and I get an appropriate link to the S3 bucket+object.
I cannot use the method prescribed in the rails guides: Rails.application.routes.url_helpers.rails_blob_path(item.file_attachments.first)
It errors with:
ArgumentError: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
I can pass it a host: 'http://....'
argument and it's happy although it still doesn't generate the full URL, just the path.
In development I'm using disk backed file storage and I can't use either method:
> Rails.application.routes.url_helpers.rails_blob_path(item.file_attachments.first)
ArgumentError: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
Setting host here also doesn't generate a full URL.
In production service_url
works, however here in development I get the error:
> item.file_attachments.first.service_url
ArgumentError: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
and specifying a host doesn't help:
item.file_attachments.first.service_url(host:'http://localhost.com')
ArgumentError: unknown keyword: host
I've also tried adding
config.action_mailer.default_url_options = { :host => "localhost:3000" }
config.action_storage.default_url_options = { :host => "localhost:3000" }
Rails.application.routes.default_url_options[:host] = 'localhost:3000'
with no success.
My question is - how can I get the full URL in a manner that works in both development and production? or where do I set the host at?
Active Storage’s disk service expects to find a host for URL generation in ActiveStorage::Current.host
.
When you call ActiveStorage::Blob#service_url
manually, ensure ActiveStorage::Current.host
is set. If you call it from a controller, you can subclass ActiveStorage::BaseController
. If that’s not an option, set ActiveStorage::Current.host
in a before_action
hook:
class Items::FilesController < ApplicationController
before_action do
ActiveStorage::Current.host = request.base_url
end
end
Outside of a controller, use ActiveStorage::Current.set
to provide a host:
ActiveStorage::Current.set(host: "https://www.example.com") do
item.file_attachments.first.service_url
end