Ruby on Rails app local directory usage for resourcing - ruby-on-rails

I want to use local files stored under my server (not in Rails' public directory or in the project directory) just like the public folder.
For a more brief explanation, I have an /home/server/img folder and my Rails project's root is something different. I want to be able to use these folder named "img" contents in my Rails app's, just like a resource file.
As an example;
<img src="/home/server/img">
I am using nginx to serve my app. And the img folder is mounted samba share directory.
Thanks.

I found the solution to the question I asked earlier. Thing I was looking for was, I wanted to use local files under my webserver on my Rails application. The main idea behind this is I didn't want to fill my web server's storage space with user content.
Therefore I basically created a mounted share under my server with the following script, then used Rails's File.open method in order to access this mounted directory's content.
The following functio reads the data from my UNIX based server's any directory and then sends the file to client machine with a basic HTTP communication. I placed this lines under controller function and gave a get routing under config/routes.rb
data_file = '/path/to/file'
data = File.open(File.expand_path(data_file), 'r')
send_data data.read, filename: "imageName.png", type: "image/png", disposition: 'inline', stream: 'true', buffer_size: '4096'
Here is another source explaining an answer for similar question.

Related

Rails 4: Issue Sending .txt files from local machine to Windows Share

I'm currently creating .csv files from a SQL view and writing to
#{Rails.root}/public/
which works no problem. In addition, I need to write these generated files to a Windows share in the form of:
\\NAME-APP.enterprise.company.com\Files
I've tried Net::SCP.upload, Net::SFTP.start, FileUtils, rsync, and even Dir.entries('share url here)` just to see if I can see anything in the folder, which generally results in
No such file or directory # dir_initialize
I can map my local computer to the Windows share point, in the form of:
smb://NAME-APP.enterprise.company.com/Files
but manually dragging and dropping to there isn't an acceptable solution in this case.
Feel like I've hit a wall and may be overlooking something. Have stumbled across this post but to no avail: How do I address a UNC path in Ruby on Windows?
Any advice on this is greatly appreciated.
Edit:
FileUtils.cp_r('/Volumes/Macintosh HD/Users/davidpardy/development/ror/sbb/oct31week/1a/FST-Export/public/1538791_new.txt', '\\\\NAME-APP\\Files')
doesn't return an error, but doesn't upload the .txt file to Files.
The solution is not to use FileUtils.cp_r(source_file, 'smb://...') because smb://... only represents the server address, not the mount folder on your filesystem.
In the terminal, run the mount command to find the path of the mount folder, which is what you'll use in ruby, e.g., FileUtils.cp_r(source_file, '/Volumes/mount_folder_here...').

rails as proxy for remote file download

I am having a rails application on e.g. example.com . I am using a cloud storage provider for any kind of files (videos, images, ...).
No I would like to make them available for download without exposing the url of the actual storage location.
So I was thinking of a kind of proxy. A simple controller which could look like this :
data = open(params[:file])
filename = "#{RAILS_ROOT}/tmp/my_temp_file"
File.open(filename, 'r+') do |f|
f.write data.read
end
send_file filename, ...options...
( code taken from a link ).
Point being is that I would have to download the file first.
So I was wondering if it would be possible to stream the file right away without downloading from the cloud storage first.
best
philip
I was working on this exact issue a while ago and came to the conclusion that this would not be possible without having to download the file to your server and then pass it on to the client as you say.
I'd recommend generating a signed, expiring download link that you insert into a hidden iframe whenever a user clicks a download link on your page. In this way they will get the experience of downloading from your page, without the file making an unnecessary roundtrip to your server.

Using Prawn on Heroku

We are currently working on a Rails application hosted on Heroku. We are trying to generate a PDF and push it to the user to download.
We are using Prawn to handle the PDF generation.
Our code for generating the PDF is currently:
Prawn::Document.generate #name[0]+ ".pdf" do
Followed by all of our code to generate the document. Unfortunately, this saves the document to the disk which is not possible (to the best of my knowledge) for applications hosted on Heroku.
We then push it to the user using
send_file "#{Rails.root}/"+#name[0]+ ".pdf", :type =>
'application/pdf',:filename => #name[0]+ ".pdf"
Is there any way using Prawn to directly push the download of the document to the user without saving the document to disk first? If not, are there any other gems for generating PDFs that don't require saving the file to the disk prior to sending the file?
Though this was answered long ago, I'll post for others who may want to do this.
You can also call render with no file name in current Prawn v0.13.2. A string will be returned, which can be sent to the client with send_data. The pattern is:
pdf = Prawn::Document.new
# ... calls to build the pdf
send_data pdf.render,
type: 'application/pdf',
filename: 'download_filename.pdf',
disposition: :inline
This will display the PDF in the browser. If you want instead to have the user download it, omit , disposition: :inline
Of course you only want to do this if the document is reasonably short or your system is not heavily used because it will consume RAM until the user's download is complete.
On Aspen/Bamboo, you can save the file to disk in the tmp/ directory in your application directory (possibly Rails.root.join("tmp")) or any subdirectory.
On Cedar, you can save the file to disk anywhere in your application directory, but you should still choose a subdirectory of your application's tmp/ directory anyway.
In either case, saved files are ephemeral. They are not shared between two running instances of your application; they are not kept between restarts; etc. Do not rely on saving the file in one request and then being able to access it in a second request.

Where to put private documents to use in Rails applications?

I have some template files I would like to use in my rails App. I was wondering where(under which directory) to put them given two scenarios:
They are private to my application (Only webmaster can delete, change them)
They are private to my application but also they can be managed by admins(deleted, modified)
Update after comments
Since you want to serve the files locally, just put them outside of the /public/ folder and outside of any of the /assets/ folders and you should be good. You can read more about the public and assets folders here: Section 2 How to use the Asset Pipeline Let's say:
/private/
I believe Section 11 send_file also used in the SO question linked in my original answer below is still the way for you to provide access to files through a controller rather than statically. Adapted from the docs:
send_file("#{Rails.root}/private/#{filename}",
:filename => "#{filename}",
:type => "application/pdf", #for example if pdf
:disposition => 'inline') #send inline instead of attachment
Original answer for remote serving together with send_file below
Regarding 1) files private to the application
You can lock up these private files in a system like Amazon S3 that provides authorized access as Callmeed explains in this SO question. Then only your application will be able to authorize access to a file.
Regarding 2) also accessible to admins
The problem with just using part 1) is that it unlocks the files for a limited time period during which I assume they are publicly available. So if you want to get around that, I think you need to take the solution from Pavel Shved actually in the same SO question above.
In that solution, files are provided through a route/controller that provides the binary data of the file rather than using a URL that points to the file.
Combined solution
Read the file from S3 with only your application authorized to do that access (not opening it publicly). Then provide the data directly through the controller which can authorize whomever you want.
Caveats
Providing binary data directly from the controller seems like it would kill performance of the
application if it is used often, but I've never tried it.
If you can find a more simple way to do part 1), part 2) will still work with that solution

Protecting the content of public/ in a Rails app

I'm maintaining a Rails app that has content in the public/ folder that will now need to be protected by a login. We're considering moving those folders of files into a path outside of public/ and writing a Rails controller to serve up the content.
Before we begin writing this, I was curious if anyone else has ran into this sort of problem? I looked for some gems / plugins that might already do this but didn't find anything. Has anyone created a gem for this?
I've done this on a site where people pay to download certain files, and the files are stored in RAILS_ROOT/private. The first thing to know is that you want the web server to handle sending the file, otherwise your app will be held up transmitting large files and this will quickly bring your site to a halt if you have any kind of download volume. So, if you need to check authorization in a controller, then you also need a way to pass control of the download back to the web server. The best way of doing this (that I know of) is the X-Sendfile header, which is supported by Nginx, Apache (with module), and others. With X-Sendfile configured, when your web server receives a X-Sendfile header from your app, it takes over sending the file to the client.
Once you have X-Sendfile working for your web server, a private controller method like this is helpful:
##
# Send a protected file using the web server (via the x-sendfile header).
# Takes the absolute file system path to the file and, optionally, a MIME type.
#
def send_file(filepath, options = {})
options[:content_type] ||= "application/force-download"
response.headers['Content-Type'] = options[:content_type]
response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filepath)}\""
response.headers['X-Sendfile'] = filepath
response.headers['Content-length'] = File.size(filepath)
render :nothing => true
end
Then your controller action could look something like this:
##
# Private file download: check permission first.
#
def download
product = Product.find_by_filename!(params[:filename])
if current_user.has_bought?(product) or current_user.is_superuser?
if File.exist?(path = product.filepath)
send_file path, :content_type => "application/pdf"
else
not_found
end
else
not_authorized
end
end
Obviously your authorization method will vary and you'll need to change the headers if you're offering files other than PDFs or you want the file to be viewed in the browser (get rid of application/force-download content type).
You could use Amazon S3. You could use the controllers to generate and serve up the urls behind your secure area, and it also has a feature that basically makes resources available only for a certain amount of time once a url is generated.
Check out this url: http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAuthentication.html
AFAIK, X-SendFile is not supported by nginx. Nginx has its own extension allowing this, called X-Accel-Redirect.
You will find more information about this here :
https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/
There is also a rails plugin implementig this feature, on github: goncalossilva/X-Accel-Redirect
If you want to tie content delivery with your Rails authentication and authorization system, then you essentially have to put the content behind a controller.
If you are looking at a more simple login approach, you can handle it with HTTP Auth and settings in your hosting environment (using htaccess, for example).
Making the file available at an unpredictable URL is a simple solution currently used in some production systems.
E.g.: GitLab. The following image was uploaded to an issue of a private repository, https://gitlab.com/cirosantilli/test-private/issues/1, but you can still see it:
Note the unguessable 90574279de prefix automatically added to the URL.
Bitbucket (non-Rails) also uses this technique.

Resources