问题
Given a model that has an ActiveStorage attachment
class MyObject
has_one_attached :avatar
end
In a dev environment I am able to retrive the avatar as a StringIO object.
obj = MyObject.new( { valid params } )
file = File.open( Rails.root.join( "spec/support/images/test_image.jpg" ))
obj.avatar.attach( io: file, filename: "test_image.jpg" )
obj.save
version = obj.avatar.variant( resize: '200x200>').processed
version_url = Rails.application.routes.url_helpers.url_for( version )
download = open(version_url)
download.class
=> StringIO
When I attempt to do the same think in a test environment, open(version_url)
returns
Errno::ECONNREFUSED Exception: Failed to open TCP connection to localhost:3000 (Connection refused - connect(2) for "localhost" port 3000)
Has anyone managed to successfully download activestorage attachments within a test? How should I configure the test environment to achieve this?
My test environment already has
config.active_storage.service = :test
Rails.application.routes.default_url_options = {host: "localhost:3000"}
What have I overlooked?
EDIT
#storage.yml
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
回答1:
Stored files are accessed through the Rails application server
Active Storage attachments generate URLs that point to the application. The application URL endpoint then redirects to the real file. This decouples the physical location of the file from the URL and provides indirection which is useful for features such as mirroring.
This also means that in order to access a file using its generated URL, a Rails application server must be running...
Server does not run in test environment
The Rails test suite does not start up a server when running the tests. The tests typically don’t need one in order to run.
Errno::ECONNREFUSED Exception: Failed to open TCP connection to localhost:3000 (Connection refused - connect(2) for "localhost" port 3000)
This error occurs because the open
call tries to request the file at the server location localhost:3000
. Because there’s no server running, it fails.
Even if you start up a development server, it will still fail because the Active Storage Attachment
and Blob
records are stored in the test database, not the development database.
Bypass the app server and get a path directly to the file
In order to get access to a file or variant in your test suite, you need to bypass the application server and get a direct path to the file on disk.
The Active Storage test suite source code shows us how to do this:
blob_or_variant.service.send(:path_for, blob_or_variant.key)
View Source
This will return a file path (on disk) which you can then open using File.open
.
Fixing the example above
In the example above, change
download = open(version_url) # BAD: tries to access using HTTP
to
download = File.open( version.service.send(:path_for, version.key) )
Use stubs to avoid network requests in the test suite
If you are testing code which accesses files using HTTP, it’s best practice to stub the network call to avoid it altogether.
There’s some good examples of how to do this in RSpec here:
RSpec how to stub open?
来源:https://stackoverflow.com/questions/52071890/how-can-i-access-an-activestorage-object-via-url-in-a-test-environment