You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ActiveStorage::Current.host not set causing disk service to throw URI::InvalidURIError #40855
There's no documents about setting ActiveStorage::Current.host before generating public permanent url using the Disk service.
Reacted by InfiniteLoopEnjoyer, Kenichisuke, Amir Sharif, octobassell, Patrick Howard Wiseman, Tim Dorr, Hunter, Joseph Haig, Sebastian Kurpios, zernie and 16 more
Reacted by William Dana, Oleksandr Bratashov, zernie, Kevin Robatel, Maxence Tisserant, Ville Muittari, Oscar Mederos, Kyle Conarro, Maximilian Götz, Lucie JOSEPH and 10 more
For those using ActionController to handle requests, there is a Concern available that will set ActiveStorage::Current.host to request.base_url as a before_action:
But, this is only a partial solution as it still wouldn't work outside of your controllers.
Since I'm using Grape for my request handling, my workaround right now is to just explicitly set ActiveStorage::Current.host before I use .url. Luckily, I only use the Disk service in testing and development.
It would be ideal if we could set this value in our config, similar to how we can set url options for ActionMailer:
Reacted by Felipe Zavan, Yevhen Viktorov, Brandon Hicks, Kiryl Laktsevich, Guilherme Pejon, Sebastian Skałacki, Nick Rogers, Giorgi Mezurnishvili, Jose Ernesto Lara Rodríguez, railsoid and 7 more
Also seeing this issue. Is there any way to set this host globally e.g. via a configuration, as others have suggested? If that seems reasonable to the maintainers of Rails, I could also take a stab at implementing it myself.
Reacted by Parikshit Sharma, jl, Kiryl Laktsevich, Thiago Ribeiro, lapser, mahendra choudhary, Giorgi Mezurnishvili and Ola Tuvesson
Presumably #39566 will resolve this by creating a system for URLs outside of the controller context. I'm not sure of a workaround for now, as we punted on our AS work once we ran into this issue.
Reacted by Ryan Seys, Mu-An Chiou, Dainel Vera and Oscar Mederos
rails 6.1.3.1
Using rspec-support 3.10.2
Using rspec-core 3.10.1
Using rspec-expectations 3.10.1
Using rspec-mocks 3.10.2
Using rspec 3.10.0
I added your lines in my rails_helper.rb but it is still nil. I also placed ActiveStorage::Current.host = "http://example.com in the model itself, without success:
WON'T WORK
class User
ActiveStorage::Current.host = "http://localhost:3000"
def main_image_thumb_url
main_image.variant(thumb_options).url
end
end
ONLY when I place that right before calling the .url method, then my tests pass:
WORKS
class User
def main_image_thumb_url
ActiveStorage::Current.host = "http://localhost:3000"
main_image.variant(thumb_options).url
end
end
What I've done now is placing include ActiveStorage::SetCurrent in my ApplicationController. But I am not sure if this how it should be...
Normally I expect that this should be set magically in the background.
Reacted by Nankai Pan, Daniel Lurie, Antony Carl Sastre, Kris Leech, Pavel Kalashnikov, Cody Braun, Dejan Stokanic, Maurice Ferguson, Rob Aldred and Maksym Prokopov
I've encountered similar problem, related to behavior of ActiveStorage::Current.host when you use Fibers (we do).
I'm thinking it might be worth a separate issue. I'm not sure though, so for now mentioning it here.
Basically the problem is this:
spec/spec_helper.rb
config.before do
ActiveStorage::Current.host = "https://example.com"
end
And it works fine. Unless we use Fibers:
example_spec.rb
it "check ActiveStorage::Current host with Fibers" do
fiber = Fiber.new do
Fiber.yield "ActiveStorage::Current:host in Fiber - #{ActiveStorage::Current.host}"
end
puts fiber.resume
puts "ActiveStorage::Current:host out of Fiber - #{ActiveStorage::Current.host}"
end
Result:
ActiveStorage::Current:host in Fiber -
ActiveStorage::Current:host out of Fiber - https://example.com
So now my tests for cases when Fibers are used fail unless I set the ActiveStorage::Current.host = "https://example.com" if Rails.env.test? in the code, right before I'm calling the blob.url. Which is of course awful.
Which stores the settings on a Fiber local variable hence when you create a new Fiber you loose this value (Same applies for a new Thread)
If helps you can workaround this by storing Thread.current[:current_attributes_instances] in a local variable and then restoring it manually:
it"check ActiveStorage::Current host with Fibers"dolocal_current_attributes=Thread.current[:current_attributes_instances]fiber=Fiber.newdoThread.current[:current_attributes_instances]=local_current_attributesFiber.yield"ActiveStorage::Current:host in Fiber - #{ActiveStorage::Current.host}"endputsfiber.resumeputs"ActiveStorage::Current:host out of Fiber - #{ActiveStorage::Current.host}"end
#39566 would definitely help, until we'll have that feature I was wondering if showing a more meaningful error when ActiveStorage::Current.host is nil would help, @zzak what's your take on this?
moduleCoreExtensionsmoduleActiveStoragemoduleBlobmoduleServiceUrldefservice_url(*)ifRails.configuration.active_storage.service == :localh="http://#{Rails.application.routes.default_url_options[:host]}"
::ActiveStorage::Current.set(host: h){super}elsesuperendendendendendend# The service_url method does appear to work with the active storage "disk" service# This monkey patch is applied in development and test onlyif%w[developmenttest].include?(Rails.env)ActiveSupport.on_load(:active_storage_blob)doprepend(CoreExtensions::ActiveStorage::Blob::ServiceUrl)endend
Reacted by kevin, Gauthier Desplanque, David Muñoz, Ari Karim, Adam Lutz, Guilherme Pejon, Damian Wdowiak, Thiago Ribeiro, Gleydson Tavares, Mateusz Walczak and 6 more
@intrip I think just inheriting the application url would help yes. Alternatively attachment.url should not raise an exception if ActiveStorage::Current.host is nil but a warning instead? 🤷
@intrip I think just inheriting the application url would help yes. Alternatively attachment.url should not raise an exception if ActiveStorage::Current.host is nil but a warning instead? 🤷
@zzak good point, I'd start with a PR which logs a warning and returns nil when .url is not set, ok for you?
@intrip One more question before you start any work, would returning nil have other consequences like on peoples test suites because of the behavior change? 🤔
After giving it some thought I think the correct solution would be just replacing ActiveStorage::Current which is a per-thread config, for a global config in the DiskService definition (it only applies here). Something like:
I encountered this issue when using local disk for tests only. Development and production both use S3.
To resolve it, instead of including module ActiveStorage::SetCurrent in ApplicationController - which wasn't needed for dev and prod. I've used the lazy load hook on_load in file test_helper.rb, including the module in action_controller e.g.
# Sets ActiveStorage::Current.host for tests using local diskActiveSupport.on_load:action_controllerdoincludeActiveStorage::SetCurrentend
Please let me know if this is not advised. Thanks
Reacted by Jordi Beltran, Alessandro Stein and nico
Reacted by Abdo, David Runger, Benjamin Wols, André Menezes and Alessandro Stein
Another clean solution is to implement a custom Active Storage service, extending ActiveStorage::Service::DiskService, and overriding #url_options. For instance:
# lib/active_storage/service/disk_with_host_service.rbrequire"active_storage/service/disk_service"classActiveStorage::Service::DiskWithHostService < ActiveStorage::Service::DiskServicedefurl_optionsRails.application.default_url_options# or something else for greater flexibilityendend
I also had this issue when trying to access model.my_attachment.url outside of a controller in development. This workaround does the trick for me and I think its neat enough.
We're seeking to solve this via #42520. Agree it's a problem. There are plenty of times where you want a ActiveStorage url generated outside of the request cycle, and we need to set that url root somewhere.
Reacted by Daniel Rice, Benno Bielmeier, Julien De Coster, ker ker, Dillon, Hairok, czepesch, Janusz Mordarski, Noah Harrison, Alexander Makarenko and 1 more
Reacted by Gaurav Khanna, David Alejandro, Jose Galisteo, Michael Baker, Dillon and André Menezes
Reacted by Ryan Seys, Viktor Schmidt, Dillon, Matthew Millsaps-Brewer, Jordi Beltran and ArimitsuYuasa
This issue has been automatically marked as stale because it has not been commented on for at least three months.
The resources of the Rails team are limited, and so we are asking for your help.
If you can still reproduce this error on the 8-0-stable branch or on main, please reply with all of the information you have about it in order to keep the issue open.
Thank you for all your contributions.
I'm struggling to figure out how to configure this for ActiveJob.
I'm doing a Turbo Broadcast via an ActiveJob (so outside a request), and my test suite uses the :test ActiveStorage service.
When running my tests, I keep getting:
ActionView::Template::Error:
Cannot generate URL for #{filename} using Disk service, please set ActiveStorage::Current.url_options. for #{partial_path}
I've got include ActiveStorage::SetCurrent in ApplicationController, but that's not helping me for this job, since it's outside of the request.
In production we use a cloud host via the S3 gem, so that's not an issue there. But these local tests that use the Disk adapter need some way of generating a url via a job.
I've tried putting this in my config/environments/test.rb, but it didn't help.
I think the problem is that ActiveStorage::Current is an ActiveSupport::CurrentAttributes, so it's being wiped every job run. I guess I need to set it somewhere else. Maybe a before_perform in the ApplicationJob.
I was having troubles with this in a test that returned an ActiveStorage blob url (record.blob.url(expires_in: 1.day)) in a Sidekiq worker. Instead of doing what I suggested above, this in spec/rails_helper.rb works:
It seems strange that this isn't the default though. I understand possibly wanting to override the url options for ActiveStorage, but why not default to the application's default url options?
Activity
daqing commentedon Dec 16, 2020
There's no documents about setting
ActiveStorage::Current.hostbefore generating public permanent url using the Disk service.timdorr commentedon Jan 6, 2021
Interestingly, Rails doesn't see this in their test suite because they set this value during setup:
rails/activestorage/test/test_helper.rb
Lines 52 to 54 in 9492339
For Rspec users, you can workaround this by setting it the same way in a spec helper:
hunterbmiller commentedon Jan 7, 2021
For those using ActionController to handle requests, there is a Concern available that will set
ActiveStorage::Current.hosttorequest.base_urlas abefore_action:https://github.com/rails/rails/blob/master/activestorage/app/controllers/concerns/active_storage/set_current.rb
But, this is only a partial solution as it still wouldn't work outside of your controllers.
Since I'm using Grape for my request handling, my workaround right now is to just explicitly set
ActiveStorage::Current.hostbefore I use.url. Luckily, I only use the Disk service in testing and development.It would be ideal if we could set this value in our config, similar to how we can set url options for ActionMailer:
config.action_mailer.default_url_options = { host: 'localhost:3000' }Perhaps there is a better way?
ryanseys commentedon Mar 16, 2021
Also seeing this issue. Is there any way to set this host globally e.g. via a configuration, as others have suggested? If that seems reasonable to the maintainers of Rails, I could also take a stab at implementing it myself.
timdorr commentedon Mar 16, 2021
Presumably #39566 will resolve this by creating a system for URLs outside of the controller context. I'm not sure of a workaround for now, as we punted on our AS work once we ran into this issue.
exocode commentedon Apr 1, 2021
^^^ This approach won't work with my rSpec tests.
I added your lines in my
rails_helper.rbbut it is stillnil. I also placedActiveStorage::Current.host = "http://example.comin the model itself, without success:WON'T WORK
ONLY when I place that right before calling the
.urlmethod, then my tests pass:WORKS
What I've done now is placing
include ActiveStorage::SetCurrentin myApplicationController. But I am not sure if this how it should be...Normally I expect that this should be set magically in the background.
gat-bryszard commentedon Apr 21, 2021
I've encountered similar problem, related to behavior of
ActiveStorage::Current.hostwhen you useFibers(we do).I'm thinking it might be worth a separate issue. I'm not sure though, so for now mentioning it here.
Basically the problem is this:
spec/spec_helper.rbAnd it works fine. Unless we use Fibers:
example_spec.rbResult:
So now my tests for cases when Fibers are used fail unless I set the
ActiveStorage::Current.host = "https://example.com" if Rails.env.test?in the code, right before I'm calling theblob.url. Which is of course awful.intrip commentedon Jun 8, 2021
@gat-bryszard related to #40855 (comment)
That's because
ActiveStorage::Currentusesrails/activesupport/lib/active_support/current_attributes.rb
Line 152 in 69dfa29
Fiberyou loose this value (Same applies for a newThread)If helps you can workaround this by storing
Thread.current[:current_attributes_instances]in a local variable and then restoring it manually:intrip commentedon Jun 8, 2021
#39566 would definitely help, until we'll have that feature I was wondering if showing a more meaningful error when
ActiveStorage::Current.hostisnilwould help, @zzak what's your take on this?jasondoc3 commentedon Jun 8, 2021
For those looking for a quick fix, I've been able to workaround this by monkey patching
ActiveStorage::Blob#service_urlzzak commentedon Jun 9, 2021
@intrip I think just inheriting the application url would help yes. Alternatively
attachment.urlshould not raise an exception ifActiveStorage::Current.hostis nil but a warning instead? 🤷intrip commentedon Jun 9, 2021
@zzak good point, I'd start with a PR which logs a warning and returns
nilwhen.urlis not set, ok for you?zzak commentedon Jun 10, 2021
@intrip One more question before you start any work, would returning
nilhave other consequences like on peoples test suites because of the behavior change? 🤔intrip commentedon Jun 10, 2021
@zzak I've just found #41996, shouldn't it be expressive enough for now?
16 remaining items
santib commentedon Sep 11, 2023
After giving it some thought I think the correct solution would be just replacing
ActiveStorage::Currentwhich is a per-thread config, for a global config in theDiskServicedefinition (it only applies here). Something like:thoughts?
JDrizzy commentedon Feb 12, 2024
I encountered this issue when using local disk for tests only. Development and production both use S3.
To resolve it, instead of including module
ActiveStorage::SetCurrentinApplicationController- which wasn't needed for dev and prod. I've used the lazy load hookon_loadin filetest_helper.rb, including the module inaction_controllere.g.Please let me know if this is not advised. Thanks
mikehowson commentedon Feb 29, 2024
This fixed it from within rspec for me
mikehulbert commentedon Aug 12, 2024
I also had this issue when trying to access
model.my_attachment.urloutside of a controller in development. This workaround does the trick for me and I think its neat enough.dhh commentedon Sep 14, 2024
We're seeking to solve this via #42520. Agree it's a problem. There are plenty of times where you want a ActiveStorage url generated outside of the request cycle, and we need to set that url root somewhere.
rails-bot commentedon Dec 13, 2024
This issue has been automatically marked as stale because it has not been commented on for at least three months.
The resources of the Rails team are limited, and so we are asking for your help.
If you can still reproduce this error on the
8-0-stablebranch or onmain, please reply with all of the information you have about it in order to keep the issue open.Thank you for all your contributions.
natematykiewicz commentedon Mar 14, 2025
I'm struggling to figure out how to configure this for ActiveJob.
I'm doing a Turbo Broadcast via an ActiveJob (so outside a request), and my test suite uses the
:testActiveStorage service.When running my tests, I keep getting:
I've got
include ActiveStorage::SetCurrentinApplicationController, but that's not helping me for this job, since it's outside of the request.In production we use a cloud host via the S3 gem, so that's not an issue there. But these local tests that use the Disk adapter need some way of generating a url via a job.
I've tried putting this in my
config/environments/test.rb, but it didn't help.Edit 1:
I think the problem is that
ActiveStorage::Currentis anActiveSupport::CurrentAttributes, so it's being wiped every job run. I guess I need to set it somewhere else. Maybe abefore_performin the ApplicationJob.Edit 2:
Yeah, this fixes it:
natematykiewicz commentedon Aug 28, 2026
I was having troubles with this in a test that returned an ActiveStorage blob url (
record.blob.url(expires_in: 1.day)) in a Sidekiq worker. Instead of doing what I suggested above, this inspec/rails_helper.rbworks:It seems strange that this isn't the default though. I understand possibly wanting to override the url options for ActiveStorage, but why not default to the application's default url options?