问题
I have a downloads_controller.rb
with a single download
action which I want to trigger the download of a file that lives in a folder called downloads
which lives in a folder called download_assets
which I have added to my asset paths.
- download_assets [Added to asset paths]
- downloads
- file_1.pdf
- file_2.pdf
...
I can successfully access any files in the folder using:
http://my-app.dev/assets/downloads/file.pdf
In order to use send_file I need the file system path to this file rather than the URL. I can get the path the the root of my Rails project using Rails.root
, and the path to the file using asset_path(path)
. However, the problem is that because I'm in development, there is no file at this path. The file is stored in:
path/to/rails/project/app/assets/download_assets/downloads/file.pdf
The action:
def download
@download = Download.find(params[:id])
file_path = "downloads/#{@download.filename}.pdf"
file_path = "#{Rails.root}#{ActionController::Base.helpers.asset_path(file_path)}"
send_file(file_path, :type=>"application/pdf", x_sendfile: true)
end
To get this to work in development I need to use the following:
"#{Rails.root}/app/assets/download_assets/#{file_path}"
However this will fail in Production because assets will be precompiled and moved into assets
.
My current workaround is:
file_path = "downloads/#{@download.filename}.pdf"
if Rails.env == "development" || Rails.env == "test"
file_path = "#{Rails.root}/app/assets/download_assets/#{file_path}"
else
file_path = "#{Rails.root}{ActionController::Base.helpers.asset_path(file_path)}"
end
Is there an alternative to supplying a different path based on environment as this seems fragile?
回答1:
Yes.
In /config/initializers
create a file called say "config.yml
" Set it up like so:
config.yml:
---
## NOT a tab character. 3 spaces. (In case that affects you)
development:
path_to_uploads: /path/to/downloads/for/development
production:
path_to_uploads: /path/to/downloads/for/production
test:
path_to_uploads: /path/to/downloads/for/test
Then create a file in the same directory (/config/initializers/
) called config.rb
config.rb:
APP_CONFIG = YAML.load_file("#{Rails.root}/config/initializers/config.yml")
Hop over to your controller:
foo_controller.rb:
class FooController < ApplicationController
def download
# ...
path_to_uploads = Rails.root.to_s + APP_CONFIG["#{Rails.env}"]['path_to_uploads']
## By handing it the Rails.env object, it will return the current environment and handle selecting the correct environment for you.
end
end
There is an excellent RailsCast on using YAML to find the environment here.
Hope that helps!
来源:https://stackoverflow.com/questions/18124673/downloading-rails-assets-file-paths-in-development-vs-production