Rails3: How to use the asset pipeline to build static assets - ruby-on-rails

So I started investigating the asset pipeline in Rails3 and I have a desired use case that is somewhat off the beaten path... so I'm looking for a recipe.
I often run webrick locally for development and then run
Passenger+Apache for deployed instances of the app.
the app is configured with a suburi path, e.g. http:// server/approot/...
to make webrick paths work like deployed instances, I added map '/approot' do run app to config.ru. Now webrick is also at http:// local:3000/approot/...
The Confusion
Given this setup, I tried to use rake assets:precompile and have been having a lot of configuration problems between local, deployed -- missing files, incorrect paths, 404s in firebug, etc. Here's a smattering of solutions I've tried:
config.assets.initialize_on_precompile = false to application.rb to prevent trying to initialize the app for production, (we have several deployed environments and call them different names, ug.) when precompiling the assets.
config.assets.precompile += %w( *.js *.css ) to application.rb to include things like jquery.js and ujs and rails.js that were missing.
config.assets.prefix = "/approot/assets" to correct a problem where the map above (in config.ru) doesn't apply to assets, so assets had to be precompiled to ./public/approot/assets, but I'm not sure if that only works locally, i.e. if I deploy, will my asset paths be http:// server/approot/approot/(js|css|...)?
When precompiling assets, the rake task switches to env production, but then it is unclear from the Rails3 doc whether sprockets continues to compile on the fly locally and use those dynamic assets, or whether it will serve the static precompiled assets instead?
I tried putting config.serve_static_assets = true in environments/development.rb, but I'm not sure how this works with config.assets.compress = false and config.assets.debug = true. Setting the assets.debug to false just seems to hide the GET requests in the webrick log, although I saw a post saying that "solved the problem" [sic].
Requirments for a Recipe
So I'd like a recipe that does the following:
assets are consistently and correctly served from a path http://server/approot/assets/... whether run in passenger or webrick (i.e. deployed or local). If this isn't possible, then I can switch my local dev environment to use Passenger+Apache as well, it's not a big deal, but I just want to know if it's possible.
raw assets exist in /app/assets like normal Rails3, but when I precompile them, they work exactly the same way in deployed envs so that asset file references don't break (i.e. right now, there are a lot of refs looking for /assets/image/... when the path is clearly set up as /approot/assets/image.... (It's unclear from the Rails3 doc whether there are assumptions about deploying to root vs a suburi, e.g. http:// server/assets/... vs. http:// server/approot/assets/...)
sprockets can't be used in deployed environments (our restriction, sorry). So this means the rails3 app has to effectively look like a static asset app. I know this is what precompiled assets are supposed to do, but the pathing issues are preventing me from getting this working as advertised.
TL;DR - I feel like I'm trying a lot of separate things that might work if I only knew the right combination of them.
References
http://guides.rubyonrails.org/asset_pipeline.html#precompiling-assets
http://blog.55minutes.com/2012/02/untangling-the-rails-asset-pipeline-part-2-production/
http://blog.55minutes.com/2012/02/untangling-the-rails-asset-pipeline-part-3-configuration/
https://github.com/rails/rails/pull/3946

Ok, here's a potentially horrible answer, but it seems to work with webrick in two contexts now and it's the day after Halloween (although I haven't tried this approach in deployed slots yet).
Configuration
Unless otherwise mentioned, everything is defaults from a rails new app generation.
config/application.rb
config.assets.initialize_on_precompile = false
environments/production.rb (not really production, only used for rake asset:precompile)
config.assets.css_compressor = :yui
config.assets.js_compressor = :uglifier
environments/stage.rb (this is one of our deployed envs)
config.serve_static_assets = true
config.ru
This is the horrible part. I duplicated the map so that Rack would serve both the suburi and the root. So the controller action that shows the layout can have http:// server/approot/foo/index, while the assets within the layout can be loaded from http:// server/assets/...
map '/approot' do
run AppRoot::Application
end
map '/' do
run AppRoot::Application
end
Running it locally
$ rake assets:precompile
$ rails s
and in firebug I see the separate parts served by sprockets (all 200 OK):
GET /approot/
GET /assets/application.css?body=1
GET /assets/jquery.js?body=1
GET /assets/jquery.ujs.js?body=1
GET /assets/application.js?body=1
Ok, so now test a 'deployed' slot locally and see if the compiled assets work?
$ rails s -e stage
and then I see the correct precompiled assets (all 200 OK):
GET /approot/
GET /assets/application-xxxxxxxxxxxxxxx.css
GET /assets/application-xxxxxxxxxxxxxxx.js
Ok, so this isn't as nice as a real suburi solution and I think I'm going to have problems in deployed slots. Round 2, fight!

Related

How to show unbundled individual javascript and css of my rails web-application

I want to show unbundled javascript and css of my web-application to a UI developer. I have tried adding require 'sprockets/railties'
config.assets.debug = true
in my production.rb, but it did not work and I can still see bundled, uglified css/js in my browser sources.
I tried running my production in development mode by adding rack_env development in my /etc/nginx/nginx.conf http block, but I get Bad Request due to following error:-
invalid number of arguments in "rack_env" directive in /etc/nginx/nginx.conf:16
Please help
Did you try purging and recompiling your assets by any chance? Depending on your deploy method, production assets may not be recompiled on every deploy / application start.
rake assets:clean (rake assets:clobber) for Rails 4+
rake assets:precompile
By default, config.assets.debug = true is what controls this 'bundling' behavior.
You might also try to comment out
config.assets.js_compressor = ... or
config.assets.css_compressor = ...
if you have any of those in your production.rb.
Another reason may be any sort of external cache, depending on where you host your app: Cloudflare or Heroku Asset Pipeline Cache (those usually cache based on MD5 of your assets).
And the last but not the least is... browser cache, just in case :)

Rails 4 app with precompiled assets on Elastic Beanstalk with Puma and Nginx serving page with old asset links

I have to precompile assets locally in order for one of my JS plugins to work correctly.
Whenever I make a change to any asset and precompile, I get a new version in public/assets, and the old one is there, too. When I run locally in production mode, I am served a page with the new assets.
When I deploy to EB, the pages always contain links to the old assets.
Of course, application.html.erb uses the dynamic css link tag: <%= stylesheet_link_tag "application", media: "all" %>
production.rb contains:
config.action_controller.perform_caching = true
config.assets.compile = true
I think this must have something to do with Nginx or some sort of caching in EC2 on the html files because puma runs locally.
I have tried:
Different browser, PC, cleared cache, disable cache. It is not the browser.
Setting send file off in nginx.conf.
Setting cache expiration to -1 for html and confirmed with curl that I receive Cache-Control: no-cache
Renamed entire app/current folder. I still receive a page, but it is missing the CSS. Where are the files that are actually used after a server is started?
rake tmp:clear on the server.
Looking all over the server for any nginx or puma cache. I found nothing.
Researching for hours on end over the past 2 years.
The only thing that ever works is to rake assets:clobber, create a new EB environment, and deploy a few times. Sometimes, even that doesn't work.
Please help!
After additional countless hours of failing to solve this, I noticed a variable in the Elastic Beanstalk configuration settings that I had been changing from the default value. RAILS_SKIP_ASSET_COMPILATION - I was setting it to true since I was trying to manage the asset compilation myself. Flipping this back to false fixed my issue and significantly increased my deployment time. My third-party javascripts and gems all work correctly as well.
I still think this is a workaround because I should be able to precompile manually. However, it is good enough for me at this time.
I had a similar issue with caching assets on staging or production server. When I checked Last-Modified attribute of an asset file, for example with curl -I http://url-to-the-asset-file server returned old (cached) file.
What solve the issue was updating assets version in production.rb file. It will force assets to recompile with new MD5 hash fingerprint.
# config/environments/production.rb
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.1'
Hopefully this will help you or at least give some guidance.

Running assets precompile in Rails 4.2.5 locally creates problems with "production.rb" defaults

I've built an experimental website using Rails ver. 4.2.5.1, on a CentOS 6.6 Linux box. I followed the "Getting Started With Rails" guide, and the Weblog build tutorial,
and then made changes to use SSL, and run in production mode.
To precompile the assets (javascript and images), I ran "rake assets:clobber" to remove previous cached results, and then "rake assets:precompile". This creates the "fingerprinted" filenames (long hex string (MD5 hash?) catenated to original filenames), and drops compiled assets into ../Weblog/public/assets directory.
The "assets:precompile" process is documented in the Rails "Asset Pipeline" documentation, and the Sprockets documentation.
The documentation I followed is at:
http://guides.rubyonrails.org/asset_pipeline.html#precompiling-assets
https://github.com/rails/sprockets-rails
The "production.rb" file as generated by default using the methods in the "Getting Started With Rails" guide, does not seem to work. I start the WEBrick rails server using a two line script file, which is:
export SSL=true
rails server -b 0.0.0.0 -p 3000 -e production
I wanted to use the assets:precompile feature, and to make this work, I have made changes to the "config/application.rb" file, as per the sprockets-rails documentation, and included the line:
require 'sprockets/railtie'
I also had to made modifications to file "config/environments/production.rb" file. The default version of the file had:
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
Note that the :uglifier line was active, but the :sass line was commented out.
The default production.rb file also had this line:
# Do not fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
What I had to do to make the WEBrick server actually operate with precompile assets, in production mode, from the Linux box, was to invoke the css_compessor, and to comment out the "config.assets.compile = false" line, not toggle it. (If the assets are already locally precompiled, then I don't need or want to compile them live, I am assuming)
The changes to the config/production.rb file to make the production mode webserver operate on the CentOS box, are thus:
# Compress JavaScripts and CSS.
# config.assets.js_compressor = :uglifier
config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed
# config.assets.compile = false
And that seems to do it. Without these changes, images would not render in the browser (Firefox 44 on Windows/ Safari on iOS/ Firefox on Android 5.1.1), and the "Destroy" link (to invoke delete method and delete an article from the database of articles) would not bring up the confirmation dialog box, or do the delete action. With the above changes to production.rb it all works, so when I run the server, the image files display, and the javascript to actually run the "Destroy/delete" process is getting served up to the browser, and the tutorial Weblog website works as expected. But it won't work if "config.assets.js_compressor = :uglifier" is turned on (by removing the # comment), and it won't work if the "config.assets.compile = false" is not commented out.
As near as I can tell, the precompile is working, and the precompiled assets, with the fingerprinted info (the long MD5 hex string) added to the filenames of the image files, are being served correctly, as is the javascript.
I understand most deployments are to Heroku and AWS, so my use of my own hardware for production mode is a bit non-standard for Rails with WEBrick, but I am curious as to why. Am I missing some needed step?
Is there a different (better?) way to do the assets precompile assuming production mode is run on a local Linux box?
And is there any obvious reason why ":uglifier" is not working? Thx.

Rails not precompiling images in the app/assets/images folder?

I have some images (svg) in my app/assets/images folder. According to the Rails Guides, all the files in the assets folder should be automatically precompiled.
However, when I reference the the image using image_tag('filename'), it shows me an Sprockets::Rails::Helper::AssetNotPrecompiled error
Asset was not declared to be precompiled in production.
It tells me to declare the file to be precompiled manually, but why should that be necessary? On top of that, why does it concern itself with the production environment when I am doing everything in development?
If you added the image after you've started the server in development, restart the server. Sprockets will then precompile that image and the error will go away.
I'm pretty sure Rails doesn't support .svg yet, hence why it would ignore it.
You'll need to include the file extensions in your config/application.rb file:
#config/application.rb
config.assets.precompile += %w(.svg)
In regards the application concerning itself with the production environment, you have to remember that the precompilation process is meant for production:
The first feature of the pipeline is to concatenate assets, which can reduce the number of requests that a browser makes to render a web page. Web browsers are limited in the number of requests that they can make in parallel, so fewer requests can mean faster loading for your application.
Concantenating assets essentially means to compile your asset files into a single file, which is typically then minified.
--
Although this can be done in real-time, it's mostly the realm of static assets (which have to be precompiled). This means that if you run the rake asstes:precompile task, it will work on the development environment, unless you call RAILS_ENV=production rake assets:precompile (which sets it to the production environment for that request.
why does it concern itself with the production environment when I am doing everything in development
The application is going to run in production, not development.
Ultimately, everything you do in development should make it easier / better to work in production. In the sense of your assets, it means that you can use many of the quirks of Rails' asset pipeline, from sprockets to preprocessors such as SASS & Coffeescript
It's probably because you didn't specify the complete image name. I ran into this problem after updating the gem too. Before I just used image_tag 'some-image', but it seems that you now have to specify what type of image/extension you want to use.
Try this: image_tag 'some-image.svg'. It worked for me.
Cheers.

Rails 4 App image assets pointing to wrong CloudFront domain name

I'm running a Rails 4 app on Heroku, using CloudFront as the CDN for some image assets. I have a Production app and a Staging app. On CloudFront, I have separate distributions for Production and Staging. I'm precompiling assets locally and pushing them to Heroku.
My production.rb has the following:
# production.rb
config.action_controller.asset_host = 'xxxx.cloudfront.net'
# Use special staging CDN if pushing to staging
config.action_controller.asset_host = 'yyyy.cloudfront.net' if ENV['PUSH_TO'] && ENV['PUSH_TO'].downcase == 'staging'
So I'm specifying a different asset_host depending on if I'm pushing to staging or production.
However, when I push to staging, the resulting images are missing and pointing to the Production CloudFront distribution.
I put some logging statements in the app to ensure that config.action_controller.asset_host is set to the correct Staging distribution.
If I manually access the image urls by changing the host from the Production host to the Staging host they work, so I know the fingerprints updated correctly.
My .css.scss.erb file contains:
.importance1 { background-image: image-url("<%= asset_path 'myImage1.png' %>"); }
I made sure to clear my public/assets and tmp folders.
So what could be causing my assets on Staging to be pointing to the wrong CloudFront distribution?
Update: I've discovered that only the assets that are referred to with asset_path from other assets (css files) are getting the wrong CDN host. Meanwhile, assets that are displayed from views using image_tag are working fine. This makes me think that the problem is during precompiling assets, the wrong url's are getting output from asset_path in the css files. Not sure why though. I'm calling rake RAILS_ENV=production assets:clean assets:precompile and like I've said, I tried modifying production.rb to explicitly use the staging CDN only as a test and it still didn't use it (the assets still point to the Production CDN.)
I finally figured out my problem.. Even though my staging app was using the correct asset_host, and the files were being served from the correct CDN, the urls within those files were pointing to the wrong CDN (the production CDN.) This was because while precompiling assets, the PUSH_TO env variable wasn't set, so the logic in my production.rb was using the production CDN. The solution was to do:
rake RAILS_ENV=production PUSH_TO=staging assets:clean assets:precompile
The key was the PUSH_TO=staging in there. This fixed all my problems!
It's clear that your conditional on this line is returning false:
config.action_controller.asset_host = 'yyyy.cloudfront.net' if ENV['PUSH_TO'] && ENV['PUSH_TO'].downcase == 'staging'
Either that or the asset_host won't allow being set twice. Don't know why that would be. Might be better to put that in an else block.
So fix that and you'll be set.
BUT....
Isn't this what environment files are for? Why don't you have this in your environments/staging.rb file? If it doesn't work there, you've fugged up your environment configuration and kinda defeated the whole purpose of multiple environments...

Resources