1

It seems impossible to make certain images private with Rails. I've searched high, I've searched low, I've asked here on SO. Got a few upvotes, but no solid response. No tutorials online. Nothing. Bags of tutorials on how to store images in the assets folder, but nothing to make images private.

Let's say I have three types of user, typeA, typeB and typeC. And let's say I have three types of images. So database schema would be as follows:

images

=> ["image_path","blob","type"]

users

=> ["name","type"]

What I want is that the users can request only the following:

typeA:

Can only view images with a type of A

Cannot view images with a type of B

Cannot only view images with a type of C

typeB:

Can only view images with a type of B

Cannot view images with a type of A

Cannot only view images with a type of C

typeC:

Can only view images with a type of C

Cannot view images with a type of A

Cannot only view images with a type of B

And yes, I could have given you the example with two types of user and image, but I really want to make sure you understand the problem; the actual system I have in mind will have hundreds of types.

I mean, I can do this in the view:

<% if current_user.type == image.type do %>
   <%= image_tag image.path #=> <img src="/assets/typaAImage.jpg" alt="..." class="..."> %>
<% end %>

but someone who isn't even a user can simply request /assets/typeAImage.jpg. and get at the image, so I really don't know what to do.

Can I prevent people browsing the public assets directory? Stop all access to the directory apart from the application itself?

If not, how can I make the images private?

I'd like answers for:

Doing this on Heroku. (postgres )

Doing this on a VPS ( postgres, nginx )

Community
  • 1
  • 1
Starkers
  • 10,273
  • 21
  • 95
  • 158

1 Answers1

3

What I personally do:

Keep the private images in a special folder, NOT under public.

Serve them through Rails, NOT through Nginx/Apache. Like this:

class MyController < ApplicationController
  def get_secret_photo
    if current_user.has_the_right_permissions?
      send_file(File.join(Rails.root, 'special_folder', 'image_name.png'))
    else
      render status: :forbidden, nothing: true
    end
  end
end

Problem solved!

Alex D
  • 29,755
  • 7
  • 80
  • 126
  • Wow, that's so much simpler than I thought it would be :) – Starkers Mar 28 '14 at 20:48
  • So the `send_file` method can be used to show images via an `` tag? I thought it was for initiating a download of the image... (you know what I mean, into the downloads folder) – Starkers Mar 28 '14 at 20:50
  • Hi, @Starkers! Do you know what an `` tag actually does? It tells your browser, "make a request for this file, and then display it in this web page". What the `send_file` method does: it reads a file from the hard drive, and puts the contents of that file in the body of your HTTP response. That may initiate a "download" in some contexts, yes, but it's also exactly what is needed for an ``. It is no different from what Apache/Nginx/etc. do when returning an image file in an HTTP response. – Alex D Mar 29 '14 at 10:24
  • Ah okay this seems like a good plan. For the +250 bounty, do you reckon you could show me how to correctly implement this? I gather I'd have to have a custom route that would link to the above action for example.. – Starkers Mar 31 '14 at 20:27
  • Yes, you will need a route. Probably you will want to pass the image name in as a parameter. What else did I miss? – Alex D Mar 31 '14 at 21:07