How to make Apache+Passenger and Rails Asset Pipeline work together nice?
When I deploy my locally working project, I get a 500 error
In ActionView::Template::Error occurred in pages#start: jquery-ui-1.8.21.custom.min isn't precompiled
If I grep my_project/current/assets_manifest.yml for jquery-ui-1.8, it gives me
jquery-ui-1.8.21.custom.min.js: jquery-ui-1.8.21.custom.minc50ea0bef9c2fae04ab3b50ead60fc1f.js
and this file also exists in my_project/shared/assets (along with jquery-ui-1.8.21.custom.min-c50ea0bef9c2fae04ab3b50ead60fc1f.js.gz, jquery-ui-1.8.21.custom.min.js, jquery-ui-1.8.21.custom.min.js.gz).
When I open
http://mytestserver/assets/jquery-ui-1.8.21.custom.min-c50ea0bef9c2fae04ab3b50ead60fc1f.js
in browser it gives me the correct js file.
The 500 error is raised from
app/views/layouts/application.haml:25
line 24-26 of that file are:
= javascript_include_tag "application"
= javascript_include_tag "jquery-ui-1.8.21.custom.min"
= csrf_meta_tag
So what could have gone wrong? Why is it not working?
If the file isn't being loaded by application.js then you need to add a line to application.rb so the app knows about it:
config.assets.precompile += ['jquery-ui-1.8.21.custom.min.js']
shared/assets is not a place that the asset pipeline typically looks for files.
Typically the asset pipeline looks in app/assets, it may look in lib/assets and I'm pretty sure it looks in vendor/assets also. But it's possible that the vendor/assets is not included by default, which I talk about below.
Per Rails convention I suggest you put that dependency in vendor/assets/javascripts
If you want to add search directories to the asset pipeline it's just a simple modification to config.application.rb
in the YourProject::Application declaration, add:
config.assets.paths << Rails.root.join("vendor/assets/javascripts")
Or whatever other path you want.
I think I solved it.. I think this were the steps:
renaming the rake-namespace of capistrano deployment (possible duplication of namespace and var damage) which was also doing the precompilation
add each js file that I include via javascript_include_tag to config.assets.precompile for production environment like #Simon suggested
in config.assets.precompile they seem to be mentioned without .js-extension, whereas in the javascript_include_tag directives they should be included with .js-extension
Related
The Problem
I'm using Semantic UI, the app renders icon fonts perfectly in development:
But don't work in production:
Error Details
In development, this file is available at:
http://localhost:3000/assets/semantic-ui-css/themes/default/assets/fonts/icons.woff2
In production, I get these errors:
planetlauncher.herokuapp.com/:1 GET
https://planetlauncher.herokuapp.com/assets/themes/default/assets/fonts/icons.woff
planetlauncher.herokuapp.com/:1 GET
https://planetlauncher.herokuapp.com/assets/themes/default/assets/fonts/icons.ttf
404 (Not Found)
Background
Webpack was installed bundled with the rails new --webpack:react command.
Semantic UI installed via yarn add semantic-ui-css
Application.css includes:
*= require 'semantic-ui-css/semantic.min.css
assets.rb includes:
Rails.application.config.assets.paths << Rails.root.join('node_modules')
Rails.application.config.assets.precompile << /\.(?:svg|eot|woff|ttf)$/
Also, I cannot precompile assets and must fallback to the heroku assets pipeline because of my react web pack dependence.
I got around this by compiling the assets with webpack - you're already using webpack, so it shouldn't be a big deal.
Create a pack for the stylesheets:
/app/javascript/packs/stylesheets.js
import 'semantic-ui-css/semantic';
Then in your layout (/app/views/layouts/application.html.erb for example):
<%= stylesheet_pack_tag "stylesheets", :media => 'all' %>
I think maybe you forgot compile your assets. So, your assets is not available in production enviroment.
$ RAILS_ENV=production bin/rails assets:precompile
http://guides.rubyonrails.org/asset_pipeline.html#precompiling-assets
Hope it helps.
Turns out this is a known issue. One of the comments explains this best:
css in node_modules will not work because it's referenced by for example url('asset.css') rather than asset-url('asset.css') (which would get the fingerprinted url)
-- Sam Peacy
I also posted this as an issue to rails/rails, and this doesn't seem to be something Rails is going to fix:
No plans to fix, neither workarounds. This problem also exists with any pure css libraries that don't use rails helpers and are not installed via yarn.
-- Rafael France
I'm trying to deploy my first Rails application, but I'm getting 404 Not found for all assets (.css, .js files and images). I tried many ways of getting things work, but nothing worked. All of the asset paths look like this:
/stylesheets/application.css
My production.rb file: http://pastebin.com/SeVNEZD9
My application.html.erb, where I include these assets look like this: http://pastebin.com/gHkpfA8Z
Thanks forward for any help.
In config/environments/production.rb file add
config.assets.digest = true
Then stylesheet_link_tag will generate fingerprints url.
You need to precompile your assets for this by running this command on terminal.
RAILS_ENV=production bundle exec rake assets:precompile
After deployment you should do
RAILS_ENV=production bundle exec rake assets:precompile
Since this is your first Rails app, let me explain where your problem might be:
When you create your assets, they reside in the asset pipeline. This
is a folder located at /app/assets where your asset files will be
stored
If you want to use assets in production, there are two ways to do it -
the first is to use the assets dynamically, or to use them as static
(which is where you precompile). When you use the likes of Heroku etc,
you need to use static assets, which is why they precompile them for
you when you deploy
The problem with static assets is that Rails creates fingerprints
for them. These fingerprints basically give them a unique identifier
which you have to dynamically reference using <%= asset_path %> etc
Your problem is likely caused by you not accessing the precompiled assets correctly. The way to fix this is to use asset tag helpers like this:
#app/views/layouts/application.html.erb
<%= stylesheet_link_tag "application" %>
<%= javascriot_include_tag "application" %>
It looks like it's working now. I needed to restart the server to apply the changes. Can anybody tell me why is it that I have to restart the server to apply such changes? I want to avoid it in the future.
I'm posting my production.rb file for those who face similar problems: http://pastebin.com/7Uskvcuc
I added a file named mobile.css into my assets/stylesheets directory. This file is not required in application.css as I only explicitly add it by pages I want optimized for mobile. When I run rake assets:precompile it doesn't push it into the asset pipeline. I'm going to guess if I add it to application.css it'll precompile, but then my mobile stylesheet will override the default stylesheet which I do not want.
Works great in development mode with the following in my layout:
- if mobile_device?
= stylesheet_link_tag "mobile"
In production this is a no go as mobile.css is not getting added to the pipeline.
What's the best way to handle this?
You can always add it manually to the precompile array in your application.rb.
config.assets.precompile += %w( mobile.css )
Rule of thumb as far as the asset pipeline is concerned: if it's not required in a manifest OR it's not in the precompile array, it's not going to be precompiled.
Could I run rake assets:precompile for specific JavaScript file?
Otherwise the full precompile lasts for 5 minutes and makes quick changes in JavaScript files very annoying.
If you wanted to precompile just one file, you could make a custom rake task to do so fairly easy.
namespace :assets do
desc "compile one js file"
task :compile_one_file => :environment do
dest = "#{Rails.root}/vendor/assets/javascripts/compiled/"
js_asset = "your_jsfile.js"
File.write(dest + js_asset, Uglifier.compile(Rails.application.assets.find_asset(js_asset).to_s))
end
end
then from the command line
rake assets:compile_one_file
Hope this helps, I find this useful for vendor js files that I don't change often such as jquery and jquery plugins. That way when im in development it speeds up my page loads keeping the asset pipeline from having to route all the separate requests for my vendor files. It just serves up one minified js file of all my vendor js.
Short: You can't.
During precompilation Rails goes through the Application.js file and merges all imports into one so just changing one file is simply not possible due to the compression that goes on in there. (It doesn't do anything to files not referenced from application.js)
Next up: You should not have to run rake assets:precompile during development when doing quick fixes. Only on deployment where (depending on your patience) it should be no problem having the task run 5 minutes.
You should be using the development environment during development where asset precompilation is not necessary because Rails will serve the assets unmerged and un-minified.
If you are running the Rails build in web-server through rails s this should be by default, but you can explicitly start the rails server using:
rails s RAILS_ENV=development
If the assets are still not correctly displayed or you see errors make sure you have config.assets.debug = true
#Tigraine is partially correct. Rails 3.1+ assets are intended to be fully managed by Rails and by default all assets will be compiled down to one js and one css asset.
HOWEVER...
Compiling down to a single asset relies on the use of an asset manifest (application.js and application.css) that is processed by the Sprockets gem. By default these manifests include a require_tree directive and it's that directive that includes all the files. If you remove that directive, you've got to do a bit more work to get your assets compiled.
If you want to build separate assets you can set a config option in application.rb.
config.assets.precompile += %w( additional/asset.css funky/stuff.js )
The above line would add the files additional/asset.css and funky/stuff.js to the list of files that would be produced when the assets are precompiled (Note that the '+=' is being used to extend the default list). To be as explicit as possible this means that you would have four assets precompiled: application.js, funky/stuff.js, application.css, and additional/asset.css.
That said, you might want to check out the guard-rails-assets gem. The gem is flexible in the way it supports precompiling; precompiling only changed assets is possible. I've heard some good feedback about it but not used it myself.
#Tigraine isn't correct.
It's possible, you just have to create folders and put the css files in them and import it to different files in the assets folder.
Like
application.css
*= require_self
*= require foundation_and_overrides
*= require reset
*= require_tree ./screen
Where Screen is a folder I've placed inside the stylesheet folder. like assets/stylesheets/screen/. I call the application.css with
<%= stylesheet_link_tag "application", media: "screen, projection" %>
Now, if you want to create a single css file for another layout you create that under assets/stylesheets
Like xxx.css
If you need multiple files for xxx you follow the same steps as above but the important part here is that you add this line to
production.rb
config.assets.precompile += %w( xxx.css )
Then inside the layout you add:
<%= stylesheet_link_tag "xxx", media: "screen, projection" %>
You can do this completely without Rails. This can make things run faster depending on your environment.
quick_compile.rb
require 'sprockets'
sprocket = Sprockets::Environment.new
sprocket.js_compressor = :uglifier # or read off config yml
sprocket.append_path('app/assets/javascripts') # the directory that holds you js src.
file = File.new('test_min.js','w+') # the output file path.
file.puts(sprocket.find_asset('test.js')) # the file to complie
file.close
If you just want to evalute the //= require statement, you can remove the js_compressor setting. Sprocket will concatenate the files required.
I have a JS file defined in the app - app/assets/javascripts/client/some-client.js.coffee
In my dev env I can access this file via URL - /assets/client/some-client.js
But I cannot do the same in production? ...meaning the URL does not work, what could be wrong?
In prod, you will have access only to precompiled files, if you use the default configuration.
You can define which assets to precompile in config/environments/production.rb:
config.assets.precompile += %w( some-client.js blabla.js some-client.css ) #etc...
Run rake assets:precompile to... precompile your assets.
Learn more with this guide: http://guides.rubyonrails.org/asset_pipeline.html
If you didn't find it yet, be sure that you are accessing it through <%= javascript_include_tag "some-client" %>. As the asset pipeline handles finding where it has precompiled the asset. Along with the config.assets.precomile += %( some-client.js ). Also, if the helper function can't find that in production you might want to try moving client/ to assets/javascript/client I think it looks for assets for example javascripts files in app/assets/javascripts/ lib/assets/javascripts/ and vendor/assets/javascripts/ if I understand the asset pipeline. And it looks like you don't have it in any of those files, so it may be skipping it since it doesn't see it.
EDIT:
Looks like you have it in javascripts/ sorry. The asset pipeline should traverse subdirectories.