Rails file location and access - ruby-on-rails

My root is site/home/ubuntu/workspace/
Is it possible to access file (from browser by HTTP request) located inside workspace/ without configuring routes and controllers?
Does the question on 1) depend on file extension?

you can access path to your file like this:
File.expand_path("somestuff.rb", "~/workspace")
for me this code produces path as follows:
"/home/foodie/workspace/somestuff.rb"

I have this structure:
# /home/username/Workspace/rails_project/app/controllers/application_controller.rb
require "#{Rails.root}/../test.rb
And
# /home/username/Workspace/test.rb
# Some ruby code
As you can see, test.rbfile is outside RubyOnRails Project.
For security reason, you can not access a file outside project rails from URL without defining a route. What you can do, is point a route to controller that, based on file name provided at url, require a file outside rails project.
# /home/username/Workspace/rails_project/config/routes.rb
get '/get_file/:file_name', to: 'files#show'
# /home/username/Workspace/rails_project/app/controllers/files_controller.rb
class FilesController < ApplicationController
def show
document = params[:file_name]
send_data "#{Rails.root}/../#{document}, filename: document
end
end
For more info, see:
http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_data

Without configuring routes and controllers, client can only access files in the public/ directory (it doesn't matter what the extension is). Bare in mind this: when your Rails app is run by webserver, its webroot will be the public directory, consequently to access public/file.ext you request should be webroot/file.ext

Related

Ruby on Rails file authorization under RAILS_ROOT/public

I am looking for a way of running a type of check_access to my files located under my public folder. I heard about RAILS_ROOT/private. I believe this directory provides my demands.
But I don't have deep information about it. The core idea of mine is serving files to only use which has the ability to view/download the files. Such as a posted pictures, I don't want them to be public. Currently, all the people who have knowledge of the URL pointing to the correct directory can access all files.
PS: The files under /public dir are uploaded via carrierwave gem.
Thanks.
If you need access control for your files you don't want to serve them from your public folder. Your public folder is server either by ActionDispatch::StaticFile or directly by your web server - neither of which provide the kind of access controll you want.
Instead you would create a controller which serves up the files:
class FilesController < ActionController::Metal
before_action :authenticate! # you need to implement this
before_action :authorize! # you need to implement this
# GET /files/:filename
def show
path = Rails.root.join(
'uploads', # can be any directory you want really
# avoids a malicous user being able to use for example '../../secret/password'
ActiveStorage::Filename.new(params[:file_name]).sanitized
)
if File.exist?(path)
send_file path
else
head :not_found
end
end
end
You can define the permissions in your database and then you can add a check before displaying the url of a file to the users. You shouldn't keep the files in public folder if you want them to be restricted.

How to list directory folders in rails

Hi I am newbie in rails and wanted to know any way to list folders and files for a url say public . So example user types example.com/public he gets all folders and files listed as we do in php if we start a wamp server . I need this so I can create files and have their url shared to public i.e. simply send url link online like example.com/public/test.pdf . Currently I am getting page with no routes defined .enter image description here
Thanks.
Create a controller to serve the file using a route parameter, ex.
get '/public/:filename', to: 'file#serve'
Then use the send_file method in your controller.
class FileController < ApplicationController
def serve
# For authorization:
#authorize!
# For authentication: (a way or another)
#redirect_to :access_denied unless user_signed_in?
send_file "/www/yourapp/var/files/#{params[:filename]}"
end
end
This way the file can be anywhere within your app, or even on a Cloud storage. It also gives you the ability to use authentication or authorization to check if the user has access.
Please note that this code is very simple, but there are much more options like Fog gem for Cloud storage and everything else.
See https://apidock.com/rails/ActionController/Streaming/send_file for more information.

Allow users to download a file

I've read through a number of StackOverflow threads and tutorials, and I haven't found a good, simple explanation for how to allow a user to download a file from your site.
All I want to do is add a link to one of my views which downloads a file when clicked.
I'd like to understand:
Where do I store the downloadable file in my file system? public?
Is there anything special about linking to the file in your view, or it's just a link_to?
What needs to happen in routes? It's just a get for that controller#action?
What needs to happen in the controller? In rails documentation I've read that you need to "be careful to sanitize the path parameter if it is coming from a web page," but I'm not sure exactly what that means.
Thanks!
In simple scenario, you don't need controller to download file. Just save file to public folder. Public folder is default folder for static resources there are stored compiled js, css, images files, robot.txt and so on.
If you have file monthly-report.doc. Put it to public/reports/monthly-report.doc.
In view link_to 'Donwload Report', '/reports/monthly-report.doc'
There are basically two cases:
1. The file is public and should be downloadable by anyone.
Place it in the /public directory. Remember that this is the web root - so if you have a file that lives at /public/foo/bar.baz you would link to the file with <%= link_to 'A file', '/foo/bar.baz' %>.
No routes or controllers are need since we are just serving a static file from the servers public directory.
2. The file needs access control
In this example we are dynamically servering files stored in /downloads.
# routes.rb
resources :downloads, only: [:show]
class DownloadsController < ApplicationController
# do your authentication logic here
# GET /downloads/:id
# #example
# GET /downloads/foo.bar would download a file stored at
# /downloads/foo.bar
# #raise [ActiveRecord::RecordNotFound] if the file does not exist.
# This causes a 404 page to be rendered.
def show
fn = Rails.root.join('downloads', params[:id])
raise ActiveRecord::RecordNotFound and return unless file.exists?(fn)
send_file(fn)
end
end
By using Rails to serve the download we can apply whatever access control rules we want.
The link_to is the same as any other link.
If you want to store it in public then do this in whatever controller action you want.
send_file File.join(Rails.root, 'public', 'file.extension')
You could create a downloads controller and specify that in the index then simply link_to 'Download', download_index_path or such.
If you're trying to send a file name that a user inputs, you have to sanitize it. If it's "hard coded" like the above example, then you're fine.

how should I serve a .txt file off the root of my app?

I've got a static route in my routes.rb:
match ':action' => 'static#:action'
And I have a file that's called F97F5BF1DF45427AA9399E360EXXXXX.txt. I need to provide access to this file for DCV validation for my SSL provider. I've tried a couple of locations and variations on the file name and still am not able to access the file via http://mysite.com/F97F5BF1DF45427AA9399E360EXXXXX.txt. Tried putting the file in public as well.
What do I need to do to provide access to that text file to any bot crawling the site?
Normally you should be able to serve it from the public/ directory. But if that does not work, you can simply set up a new route in config/routes.rb:
match '/F97F5BF1DF45427AA9399E360EXXXXX' => "static#foobar"
And then create a new controller serving the file
class StaticController < ApplicationController
def foobar
render "your file contents here"
end
end

Render static files in /doc in Rails

So far I have in config/routes.rb:
match 'doc/:path' => 'doc#show'
And in app/controllers/doc_controller.rb:
class DocController < ApplicationController
layout false
def show
render File.join( RAILS_ROOT, 'doc', params[:path] )
end
end
This works find for index.html and other .html files. But it doesn't serve up .css and .js files. It also doesn't serve nested files and directories such as /doc/metrics/output/index.html
How can I get Rails to serve up all static files in /doc but without simply putting a link to them in /public (so that I can autheticate the user in the controller first)?
I would recommend not serving the files through Rails at all. Serve them through your server (Nginx, Apache). You can use the X-Accel-Redirect and the X-Sendfile headers to tell Nginx and Apache to send the static file instead. The benefit of this approach is that you can still authenticate a user before allowing them access to the file. Here's the Nginx tutorial:
http://ablogaboutcode.com/2010/11/19/serving-static-files-passenger-nginx/
Another option is to setup your routes like this:
match 'doc' => 'doc#show'
And pass your path as a parameter so you don't have to do nested URL matching in your routes, or handle special cases (.css, .js, .html, ...)
/doc?path=/path/to/my/document.css

Resources