rails: Active Storage Disk Service NoMethodError: undefined method `rails_disk_service_url'
I have a Rails 6.1.3.1 API-only app setup that had the test suite fail with Disk Service trying to use the .url
on an attached file.
App Background
Since the app is API-only and I still wanted to use ActiveStorage, I included the required modules in application.rb
and then told the configuration to not draw the routes; I’d provide my own via the API as needed:
config.active_storage.draw_routes = false
Troubleshooting
After digging around and trying to figure out why calling model.attachment.url
was throwing a NoMethodError
, I realized it was because I was removing the active storage routes that generated the url helpers with the missing method.
I poked around to see if I could come up with a workaround but it was basically a loop of needing to draw the routes AND having ActiveStorage::Current.host
set. Without both, it wouldn’t work. One or the other, either the NoMethodError
occurred on rails_disk_service_url
OR URI.parse
would fail as BadURI
. I tried to only set the current host for the test suite, but it needed to be defined in the main app in the controller. However, I didn’t want to define this only to run my tests.
Steps to reproduce
https://gist.github.com/lauramosher/008976882516e2795fab3632230504ca
Expected behavior
Disk service for Active Storage should correctly return class.attachment.url
.
Actual behavior
Raises: NoMethodError: undefined method
rails_disk_service_url’`
System configuration
Rails version: 6.1.3.1 and Edge
Ruby version: 2.7.1, 3.0.0, 3.0.1
Conclusion
I’m putting this out as a possible bug / issue with Disk Service and API-only applications. I’d be surprised if I’m the only one having this issue, but I do realize it’s a bit niche. Let me know if I can troubleshoot more or try other stuff out!
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 15 (14 by maintainers)
@stefannibrasil Sorry I went back to re-read this thread and gain some more context.
After reading your patch I think the
disk_service_enabled?
path might be more complicated that we need.What if we just did something like
ActiveStorage.draw_routes :disk_service
and that would only draw the disk_service routes you required.So the options would be [all, disk only, or none]. /cc @pixeltrix
@lfalcao @stefannibrasil the way to do it would be to detect if the current storage adapter is using the disk service and always draw the specific routes for it. If anyone wants to have a go at fixing it then you’ll need to change the Active Storage routes to something like the following logic:
What any aspiring contributor needs to do is work out how to implement
disk_service_enabled?
. They also need to write the railties tests which ensure that this feature works and doesn’t get broken in the future.One tip - break out the full routes into a separate file and use the
draw
method to load it as demonstrated in this tweet: https://twitter.com/excid3/status/1366432061695922181hello @stefannibrasil
I don’t like the idea of conditional based on environment, as someone can use it with other environments or even production and have this problem. So, I would try to when using disk service load these required routes anyway even with
draw_routes = false
…@stefannibrasil your gist worked here fine with ruby 3.0.0p0.
@lauramosher thanks for your helpful reproduction script - always makes my life easier with one 👍🏻
The disk service is unique amongst the included services in that it reflects back on the application and not to some third-party service such as Amazon’s S3 service. So when you disable routes with
draw_routes = false
then the url helpers and routes for the disk service are not defined, leading to the error you saw. It’s possible to make your example pass by adding the following:after the
Rails.application.initialize!
line. To make it work in your application you just need to include thescope
block in yourconfig/routes.rb
file.Since the disk service is commonly used for development and testing it probably makes sense for us to draw the disk related routes irrespective of the
draw_routes
setting if the disk service is currently active. We’d probably restrict that behaviour to the development and test environments since it’s not really designed for production use and most apps run off ephemeral storage on services like Heroku.Thanks for the report - hope this information solves your problem.
@stefannibrasil Could you elaborate on how this is a breaking change? Do you mean from the current behavior or the patch you’ve wrote?
Since
draw_routes
is already either true or false, introducing a third option:disk_only
wouldn’t be breaking any compatibility afaict.I’d like to wait and see what @pixeltrix thinks of this path before making a decision and suggesting more work for you though. 🙏
Thank you very much @lfalcao @pixeltrix for your thoughts and detailed context, I appreciate it. I will work on it this week! 💪
Thank you @lfalcao and @pixeltrix I forgot to include the image file in the gist so just changing the Ruby version was enough.
I’m trying to get started with contributing more to rails. What do you think is the best way to move forward with this issue?
Thank you!
The only error I get when running your gist is the following:
Creating a blank.jpg file makes the test pass.