I've been running a Rails 3.1 app on Heroku Cedar Stack for a couple of months now. I'm using Rack::Deflater middleware to gzip my content and achieve this by
config.middleware.insert_before ActionDispatch::Static, Rack::Deflater
in my staging.rb file.
However, since last week, I get the following error when deploying to Heroku
Running: rake assets:precompile
rake aborted!
No such middleware to insert before: ActionDispatch::Static
However, running rake middleware still returns
use Rack::Cache
use Rack::Deflater
use ActionDispatch::Static
use Rack::Lock
And content served were still gzipped. However, assets were not compiled(minified) as pre-compilation failed. A manual rake precompile::asets also does not help.
So, I'm assuming ActionDispatch::Static is not available during pre-compilation of assets. So I tried to insert Rack::Deflater before Rack::Lock and now my assets are compiled without any error message but content served is not gzipped.
So, what do I need to do, to both gzip and compile my assets? What am I missing? Thanks.
Just a heads up Rack::Deflater is already used by Rails 3.1 so you don't need to manually do this.
BUT, to answer your problem here, I would assume that your production.rb has config.serve_static_assets = false set.
the ActionDispatch::Static middleware is only used when serve_static_assets is set to true. Heroku actually injects this config to override whatever you set anyway (see the Injecting rails3_serve_static_assets log message when you deploy), but I'm not sure at what stage in the deploy this happens.
So it's likely that you don't have static asset serving enabled when the assets:precompile runs (note this is just a guess, I'm not on Rails 3.1 yet so I could be wrong)
I would recommend against membLoper's suggestion of adding it manually in your rackup file:
it's not needed as explained above
your middleware that is relevant to your app should really be injected as you had originally tried in your application.rb
I still dont understand why Heroku does not recognize ActionDispatch::Static during pre-compilation of assets. However, Heroku folks did suggest a workaround to this issue.
The Rack::Deflater middleware needs to inserted in config.ru file rather than environment files. Something like,
require ::File.expand_path('../config/environment', __FILE__)
# Middleware to gzip content
use Rack::Deflater
run MyApplication
This way, it does not interfere with assets pre-compilation and still gzips the content being served.
Any resource on how config.ru works and where Rack::Deflater now resides is very welcome.
Related
I am developing Rails 5 application and use assets pipeline.
It work well in development mode, but if I try to run it in production mode, it can't load images & styles correctly.
I checked and found that it is because
config.assets.compile = false
in config/environments/production.rb
Unless I set it true, it doesn't work at all.
I know live compilation isn't good for production, what is solution?
There are two options related to serving assets within a Rails server:
Asset compilation
config.assets.compile = true
refers to asset compilation. That is, whether Rails should recompile the assets when it detects that a new version of the source assets is there. In development, you want to have it set to true, so that your styles get compiled when you edit the css files. With the next request, Rails will automatically recompile the assets. On production, you usually want to set it to false and handle asset compilation during deployment. For this, you have to run
RAILS_ENV=production bin/rails assets:precompile
Usually, if you deploy using Capistrano, it takes care of that.
Asset serving
The second option related to assets is
config.public_file_server.enabled
This describes whether it is Rails that should serve the compiled files from the public/assets directory. In development, you want that, so it's true by default. In production, you usually don't want to fire up your web server to serve the logo image or a css file, so you probably compile the assets and then host them separately (for example, on a CDN like cloudfront). If you still want them to be served in production, you can launch Rails with:
RAILS_SERVE_STATIC_FILES=true RAILS_ENV=production bin/rails server
Precompile your assets first.
Run RAILS_ENV=production rake assets:precompile to generate your stylesheets and js files in your public directory.
I am trying to understand how rails serves static files under /public, and if I get it correctly, the ActionDispatch::Static middleware is responsible for this.
However, I noticed that it's only available in development environment:
$ rake middleware
use Rack::Sendfile
use ActionDispatch::Static
use Rack::Lock
.
.
and in production:
$ RAILS_ENV=production rake middleware
use Rack::Sendfile
use Rack::Lock
.
.
How are static files served in production then? My guess is that this is handled by the web server itself (apache, puma...etc) to improve performace, is this correct?
And if that's the case, then why create a dedicated middleware for this task in development?
Thanks.
This is controlled by a setting in config/environments/production.rb:
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_files = false
The reason that this is not enabled in development, is because on development you don't need the extra functionality/overhead of nginx or apache. For example, you don't want your browser to get instructions to cache these files while developing.
ActionDispatch::Static will just load these files from disk and send them to the browser, nothing fancy. All request to public will be handled by ActionDispatch::Static, all other requests are handled by your Rails application.
I have an app which I want to deploy to Heroku. It works in development, but not when deploying to Heroku.
I am considering this to be an asset precompile issue.
But when I run bundle exec rake assets:precompile, it doesn't generate anything.
What could be the reason for this?
Seems like you overrided config.assets.precompile option and removed default values from it. Check your config/application.rb and config/initializers/assets.rb files.
Right now, every time I am changing something in the assets, I have to delete the assets folder from the public directory and then run rake assets:precompile to take effect.
Is this something right or wrong so I should put it in a capistrano task to do it automatically?
For some reason, it doesn't compile automatically the assets in production and it throws errors if I don't do the above (or it doesn't take effect the changes if there is the files already). Is there something I should put in the environments/production.rb?
Also I don't understand what the following code in the production.rb does:
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = true
I tried false and true but I didn't understand the difference.
I'm a bit confused as at how it should work the workflow in production, if what I am doing is right and about the settings for the assets in production.
Capistrano has built-in support for precompiling assets during deployment. Just add this line to your deploy.rb file:
load "deploy/assets"
I've just upgraded my app on Heroku from Rails 3.0 to 3.1, and I'm trying to make the assets pipeline work. The main issue is that I can read from the heroku log the following kind of lines, for every asset:
2011-09-03T16:35:28+00:00 app[web.1]: cache: [GET /assets/border-a3c571a354b9381740db48aeebfaa63a.jpg] miss
If I understand the pipeline correctly, this should not be "miss" for every request I make from a browser, but it should be found in the cache.
Reading the Heroku docs you can find this explanation:
Rails 3.1 provides an assets:precompile rake task to allow the compilation penalty to be paid up front rather than each time the asset is requested. If this task exists in your app we will execute it when you push new code.
But how should that "assets:precompile" task be? I tried building a project with rails 3.1 from scratch to try to find out, but there is no such task in a bare project. Or am I missing something? How could I make that the assets are found in the cache? Maybe is just an issue with configuration.
These are the options of my production config file:
config.serve_static_assets = false
config.assets.compress = true
config.assets.compile = true # If I turn this off I get a 500 error and logs say that an asset isn't compiled
My application.rb has this line:
config.assets.enabled = true
Thanks a lot for your help!
Also, take a look at http://guides.rubyonrails.org/asset_pipeline.html#precompiling-assets
For faster asset precompiles, you can partially load your application
by setting config.assets.initialize_on_precompile to false in
config/application.rb, though in that case templates cannot see
application objects or methods. Heroku requires this to be false
I was wondering the same thing, but here's a tip to help figure out if your assets are live-compiling or not
run rake assets:precompile locally
make some changes to your css but do not rerun the rake task
git add, commit and push to heroku
If the changes you made in step 2 show up on heroku, then you know your app is live-compiling
Don't forget that you are now in charge of http caching since Varnish is no longer included on celadon, so you need to set up rack-cache and memcached yourself:
heroku doc on http caching
setup rack-cache with memcached on heroku
heroku docs on memcached
But yeah, I found this puzzling too
Can you try with config.serve_static_assets set to true and
config.action_dispatch.x_sendfile_header = "X-Sendfile"
added to your config/environments/production.rb file?
When you push your code to Heroku you should see the precompiling announced by the slug compiler AFAICT.
Make sure you are on the Heroku "Cedar" stack. Then Heroku will automatically precompile your assets during slug compilation.
Note: I'm still getting "cache misses" too, but I don't think that's really true because your app wouldn't work if your assets weren't compiled.