2016-12-26 1 views
2

Я делаю webapp с платной загрузкой, и я следил за путеводителем Carrierwave за protecting uploads. Все работает как ожидающее, кроме всего прочего. Вот моя текущая настройка:Показать Rails URL-адрес несущей, не подвергая весь путь


Файл продукта Uploader

... 
def store_dir 
    "#{Rails.root}/downloads/#{model.product_id}/#{model.id}" 
end 
... 

Маршруты

get "/downloads/:product_id/:product_file_id/:filename", :controller => "products", action: "download", conditions: {method: :get} 

ProductsController

def download 
    product_file = ProductFile.find(params[:product_file_id]) 
    name = File.basename(product_file.file.file.file) 
    send_file "#{Rails.root}/downloads/#{product_file.product.id}/#{product_file.id}/#{name}", :x_sendfile => true 
end 

Проблема с загрузкой. Поскольку я указал #{Rails.root} в загрузчике файлов, файл сохраняется в папке, внешней из общей папки с именем downloads. Однако это имеет непреднамеренный побочный эффект. Когда я извлекаю URL-адрес из моей модели, я получаю полный абсолютный путь, а не путь относительно Rails Root.

Так, например, ProductFile.first.file.url возвращает "/home/doomy/Documents/resamplr/downloads/3/1/aaaa.zip", тогда вместо этого следует просто вернуть /downloads/3/1/aaa.zip.

Это поведение похоже на то, что указано в ProductFileUploader.

Например, если я изменяю store_dir на "/downloads/#{model.product_id}/#{model.id}", я получаю ошибку доступа, поскольку она пытается загрузить в корень моего ПК. "downloads/#{model.product_id}/#{model.id}" просто загружает в новую папку в каталоге public с именем downloads, что я не хочу делать.

Любые советы о том, как действовать? Благодарю.


Edit:

Я обнаружил, что установка config.root в Carrierwave конфигурационный файл в Rails.root позволяет это поведение. Если я это сделаю, в моем ProductFileUploader я могу указать store_dir как "downloads/#{model.product_id}/#{model.id}.

Однако это означает, что общедоступные файлы сохраняются с помощью ссылки «/ public/...». Rails автоматически отбрасывает имя общей папки и использует имена подкаталогов в URL-адресе.

ответ

1

Обнаружено, как это решить!

В каждом загрузчике существует специальный метод, называемый root, который мы можем использовать для установки невидимого пути к файлу. Во-первых, я создал специальный базовый класс загрузчика, называемый PublicUploader.

class PublicUploader < CarrierWave::Uploader::Base 
    def root 
    "${Rails.root}/public" 
    end 
end 

Затем я установил глобальный корень CarrierWave в Rails.root.

CarrierWave.configure do |config| 
    # These permissions will make dir and files available only to the user running 
    # the servers 
    config.permissions = 0600 
    config.directory_permissions = 0700 
    config.storage = :file 

    # This avoids uploaded files from saving to public/ and so 
    # they will not be available for public (non-authenticated) downloading 
    config.root = Rails.root 
end 

Это означает, что в моем личном файле пользователя можно просто писать

def store_dir 
    "downloads/#{model.product_id}/#{model.id}" 
end 

и это позволит сэкономить в "#{Rails.root}/downloads/..." в отличие от "#{Rails.root}/public/downloads/...". Это означает, что я могу использовать контроллер для ограничения доступа.

Однако, в моем общедоступном пользователя, я просто был ...

def store_dir 
    "public/downloads/#{model.product_id}/#{model.id}" 
end 

... потому что я хотел сохранить в моем "#{Rails.root}/public" папке. Однако, это означало, что рельсы будут показывать URL вроде следующего

/public/downloads/myfile.jpg

Это создает проблему, так как Rails опускает public с пути. Таким образом, выше было 404. Однако, когда загрузчик наследует специальный класс, где я определить root, то я могу просто сказать

def store_dir 
    "downloads/#{model.product_id}/#{model.id}" 
end 

Он будет загружать и показывать изображение правильно! Надеюсь, это может помочь кому-то.