Restricting uploaded files to logged in users with carrierwave
I’ve had this in my notes for a long time. In order to not upload files to your public/
folder, which is the default for carrier wave, it’s really simple. Just need to change a couple of things.
In your uploader, in this example documents_uploader, change the path where the files are stored. You can even do the least work and change public
to uploads
. (If you do that, make sure to exclude uploads from git and to link uploads when your application is deployed.)
# app/uploaders/documents_uploader.rb
def store_dir
# before:
# File.join(Rails.root, "public", "#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}")
# After:
File.join(Rails.root, "uploads", "#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}")
end
Second, you need to create a controller and call it something like FileController
or UploadedFilesController
. All that it needs to do is return the file.
# app/controllers/files_controller.rb
class FilesController < ApplicationController
before_action :authenticate_user!
def show
File.open(params[:id] + "." + params[:format], 'rb') do |f|
send_data f.read, :type => "image/#{params[:format]}", :disposition => "inline"
end
end
end
and in your routes
# config/routes.rb
resources :files, only: [:show]
then you can use it as follows in your views:
<%= image_tag file_url(@post.featured_photo.file.file) if @post.featured_photo?%>
A caveat regarding mime types and formats: this is the absolute simplest and quickest way of handling authentication for files but you might have issues because the show action in the files controller just blindly assumes that the type is the format and that the format is after the dot, etc, etc. There are more robust ways to handle the File.open
part but for my purpose they were not needed.