Rails serving large files - ruby-on-rails

I'm developing an application serving large videos only to logged users.
To keep these videos private i put them in a private folder inside Rails project and let Rails serve them, instead of using the public folder and excluding requests from apache (to avoid direct linking to them).
My action in the controller looks like this:
def video
respond_to do |format|
format.mp4{
send_file File.join([Rails.root, "private/videos", #lesson.link_video1 + ".mp4"]),
:disposition => :inline, :stream => true
}
end
end
Everything works perfectly, but just with small files, as soon as i try with real files i receive the error:
NoMemoryError (failed to allocate memory)
I read somewhere that is not a good practice to use send_file for large files, but using the other approach, to let apache serve the files, i had an issue serving files to mobile apple devices, as they're not sending the HTTP_REFERER.
Do you have any idea on how small is this memory limit?
My videos are from 400MB to 2GB (trying to reduce them).
The only question i found here is without an answer serving large media files from the assets folder in rails

I managed to activate X-Sendfile on Apache instead of letting Rails to serve large files. Working with Capistrano i found a good solution. Here is explained how Capistrano & X-Sendfile

Related

Run built frontend (react) as a static file in Rails

So I'm trying to run a React app as a static html file (it's index file) in a Rails app. This works in express/node and it's quite common in projects, but i can't find a solution for this in Rails. So the react app is already built and i'm trying to serve it as a static html from the /public folder. EDIT However i can't get it to run, it shows me that it's loaded, there's no error in the rails console or the browser console, however nothing gets shown on the screen.
routes.rb
get "react_app" => "projects#react_app"
projects_controller.rb
def react_app
render :file => 'public/react_app/public/index.html'
end
i also have
config.serve_static_assets = true
I'm using Rails 5.2. I am not using yarn, i'm trying to run it via the plain assets pipeline.
Any ideas ? Or is there another better way to do it maybe ?
This app needs to be all in one place, and unfortunately gems such as react-on-rails or react-rails are not an option, since they require too much strange customization and often crash due to Redux.

Managing access to a file with a direct link

I have a rails app where I upload files. I'm using gem cancan for managing access to files. The files are stored on the disk. Is it possible to manage access to a file or restrict/allow it even when a user has a direct link to it? Note I'm not using nginx or apache, it's a local application, therefore at best it's unicorn or simply the standard Rails web server.
Yes, it's possible. Move your files out of public folder, which is served by by your web server, to some other folder (private for example) and use send_file in controller to transmit data. Some pseudo-code for controller:
def get_file
absolute_path = Rails.root + 'private' + params[:filepath]
if current_user.allowed_to_download?(params[:filepath]) && File.exists?(absolute_path)
send_file absolute_path, status: 200 # ok
else
render status: 403 # forbidden
end
end
You will have to setup route for this action, but basicly that's all.

Rails + Paperclips + Rackspace CloudFiles with the Private CDN

I have a Rails application that uses Paperclip to handle uploaded files and we are currently hosted by Rackspace.
The application is currently hosted on a single server and I am building out a more scalable solution with load balancers, application servers, and a separate database server. The last thing I need to do is a solution for the uploaded assets. I have tried to use Rackspace's CloudFiles, but it seems the only way to use paperclip and CloudFiles is to have them on the public CDN, which I can't use, a user needs to be authenticate to access the files. Before I turn to Amazon S3, since they have the option for temporary URLs, does know how to use CloudFiles with Paperclip and require authentication to access the files?
Any help, tips, google searches, links, or solutions would be greatly appreciated.
As it happens, Cloud Files also supports the generation of temporary URLs, and it appears that Paperclip does allow you to make use of it. Just generate the URL from your Attachment with #expiring_url instead of #url in your views:
= image_tag #organization.logo.expiring_url(Time.now.to_i + 100, :original).gsub(/^http:/, "https")
Paperclip will only generate http urls, but since Rackspace's temporary URLs don't use the scheme in their checksums, you can use a gsub call to turn it into an https URL. Also, notice that the first argument to #expiring_url is an absolute timestamp (in seconds-since-the-epoch).
Expiring URLs for Rackspace only made it into fog somewhat recently -- v1.18.0 -- so if you're using an older version, you may need to upgrade fog to take advantage of them:
bundle upgrade fog
Paperclip also supports generating obfuscated URLs, which looks interesting, but would be less secure, since the server wouldn't expire it.
You can add the key like this:
class Rackspace
def self.add_temp_url_key
require 'fog'
puts "Creating Storage Service"
begin
service = Fog::Storage.new(
:provider => 'rackspace',
:rackspace_username => ENV['FOG_USERNAME'],
:rackspace_api_key => ENV['FOG_API_KEY'],
:rackspace_region => ENV['RACKSPACE_REGION'].to_sym
)
service.post_set_meta_temp_url_key(ENV['RACKSPACE_TEMP_URL_KEY'])
puts "X-Account-Meta-Temp-Url-Key successfully set to #{ENV['RACKSPACE_TEMP_URL_KEY']}"
rescue => e
puts "Unable to set X-Account-Meta-Temp-Url-Key - #{e.inspect}"
puts e.backtrace
end
end
end

Restrict access to images in Rails app

I have rails project. In my project I load images on server (rails 3 + paperclip + devise + cancan). I want to limit access to files (for example, the original image can be viewed only by the administrator). How should I do it?
If you are limiting by an attribute in your database then one way would be to serve the image via a controller. It's not the most performant but it is secure.
I haven't tried this out, but if you were serving the image from a URL like
/images/picture_of_mickey_mouse.png
then you could create a route in your app that responds to /images with a filename attribute and serve all those images through a controller.
e.g.
class ImagesController < ApplicationController
before_filter :authenticate_admin!, :only => [:show]
def show
send_file "/images/#{params[:filename]}", :disposition => 'inline'
end
end
You would want to make sure you sanitize the params[:filename] however, otherwise the user would be able to download any file on your server!
The docs on send_file are here: http://apidock.com/rails/ActionController/DataStreaming/send_file
Files are handled with ActionDispatch::Static. IMO the best solution is provide similar middleware (basing on Rails source code) but with some authentication and insert it before ActionDispatch::Static. This would work with Warden-based solutions (like Devise) since they do authentication in middleware; just ensure your middleware is put after Warden and old plain ActionDispatch::Static is run just after them.
EDIT: One more thing worth noting. It's quite common in production that Nginx (I'm not sure about Apache and others) is configured to serve all the static files by itself, without passing those requests to rack stack. You may need to disable this Nginx' feature.

Should I disable mod_rails for images and stylesheets directories?

I had a rare error in my Rails application. A CSS file was referring to non existing image files. And missing PNG file was somehow mapped to a controller action. Fortunately the action wasn't changing DB. This seems to be not OK that missing PNG can trigger controller action.
So should I disable mod_rails for static asset directories? However I've never heard this is required for Rails apps.
It is definitely a good idea, since if you allow any kind of image upload the target destination is usually the asset directory. Normally the user can quite easily upload a php or ruby file instead, so disabling all mod_evil_script for these directories is a good idea in general.
You should be serving static assets directly via Apache anyway, because it's faster. Let Rails do what it's designed to do which is handle dynamic requests.

Resources