New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ActiveStorage::Current.host
not set causing disk service to throw URI::InvalidURIError
#40855
Comments
There's no documents about setting |
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: RSpec.configure do |config|
config.before(:each) do
ActiveStorage::Current.host = "https://example.com"
end
end |
For those using ActionController to handle requests, there is a Concern available that will set 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 It would be ideal if we could set this value in our config, similar to how we can set url options for ActionMailer:
Perhaps there is a better way? |
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. |
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. |
^^^ This approach won't work with my rSpec tests.
I added your lines in my
ONLY when I place that right before calling the WORKS
What I've done now is placing Normally I expect that this should be set magically in the background. |
I've encountered similar problem, related to behavior of 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:
And it works fine. Unless we use Fibers:
Result:
So now my tests for cases when Fibers are used fail unless I set the |
@gat-bryszard related to #40855 (comment) That's because
Fiber you loose this value (Same applies for a new Thread )
If helps you can workaround this by storing it "check ActiveStorage::Current host with Fibers" do
local_current_attributes = Thread.current[:current_attributes_instances]
fiber = Fiber.new do
Thread.current[:current_attributes_instances] = local_current_attributes
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 |
For those looking for a quick fix, I've been able to workaround this by monkey patching # config/storage.yml
local:
service: Disk
root: <%= Rails.root.join("storage") %> module CoreExtensions
module ActiveStorage
module Blob
module ServiceUrl
def service_url(*)
if Rails.configuration.active_storage.service == :local
h = "http://#{Rails.application.routes.default_url_options[:host]}"
::ActiveStorage::Current.set(host: h) { super }
else
super
end
end
end
end
end
end
# The service_url method does appear to work with the active storage "disk" service
# This monkey patch is applied in development and test only
if %w[development test].include?(Rails.env)
ActiveSupport.on_load(:active_storage_blob) do
prepend(CoreExtensions::ActiveStorage::Blob::ServiceUrl)
end
end |
@intrip I think just inheriting the application url would help yes. Alternatively |
@intrip One more question before you start any work, would returning |
@intrip Ah yeah, I totally missed that. Good find! |
For those searching for this error from Google, note the proper usage in views is to use "url_for" such as: url_for(profile.image) and not profile.image.url |
I fixed my rspec by adding include ActiveStorage::SetCurrent to my controller. Non of the other suggesions did anything |
Here's the handy link to the api doc in case anybody wants further research: https://api.rubyonrails.org/v7.0.2.2/classes/ActiveStorage/SetCurrent.html
|
I believe this is a great suggestion. Especially that There's even a PR #42847 which adds exactly that, sadly never merged in (I can rebase and double-check it if this is an issue). |
Another clean solution is to implement a custom Active Storage service, extending # lib/active_storage/service/disk_with_host_service.rb
require "active_storage/service/disk_service"
class ActiveStorage::Service::DiskWithHostService < ActiveStorage::Service::DiskService
def url_options
Rails.application.default_url_options # or something else for greater flexibility
end
end # config/storage.yml
local:
service: DiskWithHost
root: <%= Rails.root.join("storage") %> I believe it is usually okay to do this in test or development environments. |
Another possible solution at https://stackoverflow.com/a/76079790/ |
2023 and this is still a problem. 😡 |
The issue is closed because this isn't a problem. If you are seeing this error you are probably missing this https://api.rubyonrails.org/v7.0.2.2/classes/ActiveStorage/SetCurrent.html |
Unfortunately this solution only works when generating urls inside of your controllers. I've just gotten accustomed to setting I still feel like this is something we should be able to set inside of our configs as mentioned above, but I understand its a bit of a niche situation. |
This fixed it for me! Thank you so much! |
man you have just saved my evening ! |
This actually works and lets my RSpec test suite pass. @rafaelfranca - this really should not be necessary. There is absolutely no documentation on this hidden "feature" in ActiveStorage. Could you please prescribe how one is supposed to set Note: none of the solutions below worked in my Rails 7.0.5 application. In my opinion, these solutions are better and more intuitive than creating a custom Disk Service so why wouldn't they work in the In # Store uploaded files on the local file system in a temporary directory.
config.active_storage.service = :test
config.active_storage.url_options = { host: 'www.example.com' } In RSpec.configure do |config|
config.before(:each) do
ActiveStorage::Current.url_options = {host: 'https://example.com'}
end
end |
Hey all, I think I now understand why setting Not sure if this happens just in RSpec or in Minitest as well. I'm wondering why we are calling
Does this make sense or am I missing something? Anyways I got it fixed by doing this: # spec/rails_helper.rb
Rails.application.executor.to_complete do
ActiveStorage::Current.url_options = { host: ENV.fetch('SERVER_HOST', nil),
port: ENV.fetch('PORT', 3000) }
end |
I'll leave here a reproduction script. @rafaelfranca If you agree this is something we should fix, I'm willing to help. # frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Activate the gem you are reporting the issue against.
gem "rails", "~> 7.0.0"
gem "sqlite3"
end
require "active_record/railtie"
require "active_storage/engine"
require "tmpdir"
class TestApp < Rails::Application
config.root = __dir__
config.hosts << "example.org"
config.eager_load = false
config.session_store :cookie_store, key: "cookie_store_key"
config.secret_key_base = "secret_key_base"
config.logger = Logger.new($stdout)
Rails.logger = config.logger
config.active_storage.service = :local
config.active_storage.service_configurations = {
local: {
root: Dir.tmpdir,
service: "Disk"
}
}
routes.draw do
get "/" => "test#index"
end
end
class TestController < ActionController::Base
include Rails.application.routes.url_helpers
def index
render plain: "Home"
end
end
ENV["DATABASE_URL"] = "sqlite3::memory:"
Rails.application.initialize!
require "minitest/autorun"
class BugTest < Minitest::Test
include Rack::Test::Methods
def test_doesnt_clear_active_storage_current
ActiveStorage::Current.url_options = { host: 'localhost', port: '3000' }
get "/"
assert_equal({ host: 'localhost', port: '3000' }, ActiveStorage::Current.url_options)
end
private
def app
Rails.application
end
end |
After giving it some thought I think the correct solution would be just replacing # config/storage.yml
local:
service: Disk
root: <%= Rails.root.join('storage') %>
url_options:
protocol: 'http'
host: 'localhost'
port: '3000'
# ... thoughts? |
I encountered this issue when using local disk for tests only. Development and production both use S3. To resolve it, instead of including module # Sets ActiveStorage::Current.host for tests using local disk
ActiveSupport.on_load :action_controller do
include ActiveStorage::SetCurrent
end Please let me know if this is not advised. Thanks |
This fixed it from within rspec for me |
Steps to reproduce
config/storage.yml
:config/environments/development.rb
:app/models/user.rb
:Expected behavior
In rails console:
Actual behavior
In rails console:
System configuration
Rails version:
Rails 6.1.0
Ruby version:
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
The text was updated successfully, but these errors were encountered: