I have an action, that generates a PDF files and save it in the /public/output.pdf.
When I set
config.serve_static_assets = false
this file can't be found.
What's wrong ?
From the documentation:
"config.serve_static_assets configures Rails itself to serve static
assets. Defaults to true, but in the production environment is turned
off as the server software (e.g. Nginx or Apache) used to run the
application should serve static assets instead. Unlike the default
setting set this to true when running (absolutely not recommended!) or
testing your app in production mode using WEBrick. Otherwise you won´t
be able use page caching and requests for files that exist regularly
under the public directory will anyway hit your Rails app."
Which means that if you set that to false Rails will not serve any assets from your public folder as it is assumed that a front-end web server (apache/nginx) will handle it. This lessons the load on Rails as the front-end server is much, much more efficient at serving files directly.
After testing, I came to this conclusion:
1) when using the command
rails s -e production
Rails will only serve the statics files. Any other file created after you compile your assets will not be found.
To handle this, you need to execute your application under a web server like Apache, Nginx or other. These web servers will serve this files for you.
This looks to be obvious, but not for a beginner.
Related
I have been handed a Ruby Project that creates a document and serves it to the user, when I try to access the file on a local environment it it is delivered correctly, (this is the code that does so).
filepath = Rails.root.join("public",#records.document.url)
send_file (filepath)
So I know the file is constructed correctly and sending it to the user using send_file works at least in a local environment.
But when it's deployed on the production server (running Amazon EC2, ubuntu, deployed with dokku) I get a 500 Internal server error:
ActionController::MissingFile (Cannot read file *path of the file*)
Few things I'm noticing: doing a find / -iname "*filename*" tells me the file is stored in var/lib/docker/overlay2/*container_name*/merged/app/public/filename and var/lib/docker/overlay2/*container_name*/diff/app/public/filename but the result of joining Rails.root with the filename is app/public/filename, do I need to pass send_file the whole filepath?
I googled for a couple hours and it seems nginx has no access to the public folder because it's running in the host machine while the app is inside a container? How would I know if that is the case and if so, how should I serve the file?
The person who originally wrote the code told me to use OpenURI.open_uri() but googling it doesn't seem to turn up anything applicable to the situation.
Nothing you're doing here actually makes sense - its sounds like you're just following a bunch of misinformation down a bunch of rabbit holes.
The way this is supposed to work is that the files in /public - not /app/public are served directly by the HTTP server (NGinX or Apache) in production and your Rails application in development (so you don't have to configure a local HTTP server). The /app directory is for your application code and uncompiled assets. Do not serve files from there - ever.
The /public directory is used for your compiled assets and stuff like robots.txt, the default error pages and various icons. Serving the files directly by your HTTP server is far more efficient then serving them through your Rails application. You can do a litmus test to see if serving static assets are working by sending curl -v YOUR_URL/robots.txt.
If this isn't working in production you need to check your NGinX configuration. There is no shortage of guides on how to serve static files with NGinX and Docker.
Serving files with a Rails controller and send_data / send_file should only be done when its actually needed:
The file is not a static file or something that can be compiled at deploy time.
You need to provide access control to the files with your application.
Your proxying files from another source.
I am running the same rails 5.1.5 app in development and production. Everything works as expected in the development environment. In production, I could not serve the static assets in the public folder initially. I set the config.public_file_server.enabled = true in production.rb. However, since every request on my page is behind an authorization (as a :before_action in the application controller), the .js file that sets the authorization cookie is also not served without authorization and my service is caught in a loop. This does not happen in the development mode, and the public assets are not requested through rails routes. I need guidance on how the serving of public assets is different in development and production mode for a rails application.
Well I believe this could be due to a problem in your production configuration. For an example in Production you don't let static resources to be served by the Rails process. You should instead set static assets to be served by the Web server. You cam simply do this by adding the following configuration to you Apache or Nginx virtual files.
DocumentRoot /home/xxx/test/public
root /var/www/phindee/current/public;
I have a Sinatra app in a Rails app that serves a static asset from a directory. The app is mounted in the Rails routes like this:
mount BeanstalkdView::Server, :at => "/beanstalk"
When I run this locally it works fine, using Thin, but when I run it on my test server (Nginx/Passenger) the static assets behave strange. A request to a static file return 200 OK, but there is no content.
I tell Sinatra where my static files are via set :public_folder, "#{root}/resources" and in the template I load the static files, e.g. a CSS file with #{request.env['SCRIPT_NAME']}/css/file.css. I verified that both paths are correct.
That happens due to ::Rack::Sendfile middleware which is enabled by default in Rails 3.0.x in production (disabled by default in any environment since 3.1.x).
This middleware is really simple but yet powerful. When you pass ::Rack::File or ::Sinatra::StaticFile (or any other object) which respond to :path, this middlware adds X-SendFile (for Apache) or X-SendFile-Redirect (for NGinx) and does not sends actual body. So that Apache or NGinx will handle real file delivery. It's a good and most efficient way to serve static assets in production, however you may disable this middleware (if you don't want to mess with your Nginx/Apache config). Find and comment following config option in your config/environments/production.rb file:
config.action_dispatch.x_sendfile_header
this config option is used to instruct Sendfile middleware which header to set (do not do anything if not specified).
Aleksey V's answer helped me a lot. In the end I fixed this using the proper setting for Nginx in production.rb:
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
Make sure you restart your Rails app, Nginx and do a hard refresh in your browser to get the files.
For more info check out: http://jimneath.org/2011/04/05/rails-3-nginx-and-send_file.html.
How much ruby code deals with serving static content out of public? Does it pass through the rails app at all? Does it use Rack::Static?
Rails doesn't use Rack::Static, it has its own version, ActionDispatch::Static. You should see it if you run rake middleware.
This is only added to the Rails middleware stack if config.serve_static_assets is true. This setting defaults to true, but the default generated config/environments/production.rb turns if off.
The idea is that during development you have a simple single process that you can run and check everything is working and where performance isn't an issue, but when you deploy to production you configure your webserver (usually Apache or Nginx) to serve the static files as it is much better at that than Ruby.
If you use Heroku, their latest Cedar stack doesn't use a separate webserver for static files, so as part of the deploy process they inject a Rails plugin to serve static assets. All this plugin does is set serve_static_assets to true.
It depends. If you're using something like phusion passenger to run your app, its default behavior is to use Apache directly and skip rails for any static content. If you're using webrick (rails server) it's going to use a lot more rails/rack code to do the static serving.
A note though, if you're using apache/nginx with passenger: in production mode, since the default is to let apache serve all static content, you will need to run rake assets:precompile on the application prior to launching it in apache, or the static content doesn't get put where it needs to be for apache to get it quickly, and in a prod-ready form.
I am running a Rails 3.0.9 app on Heroku's Cedar stack and have S3 serving static assets. In my production.rb file, there was a config set to:
config.serve_static_assets = false
If I change this to true, will it serve cached content quicker, or should I leave it as is?
The answer from Rafal is not strictly correct as essentially it comes down to what stack and what version of Rails you choose to run in your application.
With Rails 3.0 on the Bamboo stack there is a Varnish cache which sits in front of the Thin processes that Heroku run. This caches any static assets and returns them without hitting your application.
With Rails 3.0 on the Cedar stack there is no Varnish cache. Therefore all requests will be hitting your Rails process regardless of whether they are static or not.
With Rails 3.1 which should be on Cedar Heroku will try to run a rake assets:precompile as part of the slug compilation process. If this fails for any reason it will inject some code into your slug meaning that static assets are compiled and served at at run time.
There is a Rails 3.1 document on the dev center which is particularly useful regarding this: http://devcenter.heroku.com/articles/cdn-asset-host-rails31
So, if you're looking for the correct setting bear this in mind. However, before you do that, notice that Heroku will alter this setting as they see fit when you do your deploy, so any setting that you do put in will be overwritten anyway during the slug compilation. Therefore it doesn't really matter what you put in here.
(and for the record, Heroku uses Nginx, you just don't tend to see it)
From rails guide:
config.serve_static_assets configures Rails itself to serve static assets. Defaults to true, but in the production environment is turned off as the server software (e.g. Nginx or Apache) used to run the application should serve static assets instead. Unlike the default setting set this to true when running (absolutely not recommended!) or testing your app in production mode using WEBrick. Otherwise you won´t be able use page caching and requests for files that exist regularly under the public directory will anyway hit your Rails app.
Hope this helps.