Rails using cached application.css despite changes - ruby-on-rails

I have a Rails 3.1 application that uses SASS. The application.css.scss file looks like:
#import 'reset.css';
#import '960.css';
#import 'pages/master.css.scss';
I have a watchr script that touches application.css.scss whenever one of the #imported files is changed.
For a while this setup worked fine. Ever since last week (and I'm not sure why), Rails has been pulling a cached version of application.css for the webpages despite all my attempts at restarting the app, re-touching application.css.scss, etc. I've also deleted .sass-cache to no effect.
Any ideas?

I had the same issue. I stopped the server, executed rm -fr tmp/cache, and my css files were finally rebuild.

First, the usual cache clearing sanity checks might help. Clear browser cache. Clear server file cache (if you're in dev/test or can afford to in production) and sass-cache :
rake tmp:cache:clear
rm -fr tmp/sass-cache #or 'compass clean' if using compass
If that doesn't help, maybe Rails compiled ANOTHER application.css elsewhere (that didn't get removed by the cache clearing)?
For example, I ran compass watch app/assets/stylesheets/application.css.scss for debugging purposes and it created a public/assets/application.css file which, by virtue of it's location in public/, prevented any new application.css.scss stylesheet changes from being noticed by Rails. Once I removed it, the application again pulled from the .scss stylesheets. This is just one example of accidental overriding file creation. Try running a find on the entire application directory looking for any generated application.css files, doing this after the cache clearing to avoid those showing up in your results.
(FYI, to avoid my specific issue, I now run compass watch with --css-dir pointed at the cache to prevent my issue
$ compass watch app/assets/stylesheets/application.css.scss --css-dir tmp/cache/
)

I've had a similiar issue after running rake assets:precompile in development. Maybe Rails is serving precompiled assets from public/assets? Try cleaning that up.
You shouldn't need to touch aplication.css.scss in development, rails should serve the new content whenever one of the #included files changes.
Also, make sure you have the following in config/environments/development.rb
# Do not compress assets
config.assets.compress = false
# Expands the lines which load the assets
config.assets.debug = true

If you replace #import 'file.css'; with #import 'file'; in your application.scss that should allow it to be auto-refreshed in development mode
I had been using bin/rails tmp:clear until I removed the file extension

To wipe out the asset pipeline cache, a brute force rm -rf tmp/* will
suffice. This has certainly fixed a few otherwise inexplicable CSS and
JavaScript glitches in my experience. As a preventative measure, it
might also be a good idea to clear the cache after upgrading gems or
changing the asset pipeline configuration, although this may just be
superstition.
Finally, if you are experimenting with rake assets:precompile in your
development environment (more on this in a later article), you’ll also
want to rm -rf public/assets/* afterwards to clean that up.
http://blog.55minutes.com/2012/02/untangling-the-rails-asset-pipeline-part-1-caches-and-compass/

You can invoke Rails automagic cache busting by doing the following:
Rename the SASS file as a partial, i.e. with an underscore prefix. E.g. _master.css.scss
Remove the extension from the import. You can keep the paths, but exclude the underscore. E.g. #import 'pages/master';
Now you can make changes in master and have them reflected without messing with the cache manually.
(Note: I'm on Rails 4.2)

I had a similar issue with Rails 6.0.3.1 today. I had to re-touch application.scss so that rails didn't use the cached version.
Running rake tmp:cache:clear helped, but it's annoying because I had to run the command every time I updated any partial scss file. :(

Random I was having a caching issue related to using twitter bootstrap and application.css.scss. Basically I changed application.css.scss to just plain application.css and fixed my problem. Maybe this can help you? If you haven't figured it out already.

I was having this problem, but I was actually putting css into application.css, rather than into files that it included. I cleared out application.css to simply include all of my css. So, my application.css now looks like this:
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the top of the
* compiled file, but it's generally better to create a new file per style scope.
*
*= require_self
*= require 'bootstrap.min'
*= require 'global'
*/
My changes are reflected any time I change one of the included files (e.g. global.css)

Related

RAILS 6 + Webpacker -- route error for packs/css|js/application-* in production environment

In development mode, all looks great. But when I switch over to production, bootstrap isn't found. When I look at the logs, I see errors like:
ActionController::RoutingError (No route matches [GET] "/packs/js/application-2a5806e943e281221741.js"):
This is true for both CSS and JS. When I look inside public/packs the files do exist in the corresponding subdirectory (js for the .js file, etc). So, webpacker is did it's job but puma isn't finding it. Any ideas? This is an old rails app that was migrated up several versions of rails, so I'm sure there is something I missed when tying everything together.
To expand on Tenzin's comment which I believe is the correct answer to the issue, Rails in development will always re-render assets and serve them. This is slow, but useful for seeing quick changes while developing.
When we want to deploy to production, the issue is Rails begins to serve static files which means that the server is no longer going to render them on every request. It will render them once and serve them forever. With webpacker, you can find the places these assets are served in webpacker.yml
public_root_path: public
public_output_path: packs
So if you are deploying or trying to run production locally, first be sure to compile your assets for production so these static files are created.
rake assets:precompile RAILS_ENV=production
Then make sure that wherever the server is running it has an ENV variable RAILS_SERVE_STATIC_FILES set to anything. As you can see from production.rb,
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
Is simply checking if this variable is present. If it is then it will not re-render as we discussed and it will look for the static files shown in webpacker.yml.
As another small note, if you are using something like a React UI or Bootstrap and the CSS is missing, be sure that you are importing the CSS according to the library's documentation.
For example, in Bootstrap, you will need to create an application.scss file in app/javascript/packs/stylesheets (really wherever in the /javascript folder) and import that in /javascript/packs/application.js.
In application.scss you'll want to
import "~bootstrap/scss/bootstrap"
This is of course after you have added Bootstrap to your package.json with something like
yarn add bootstrap

rake assets:precompile for specific JS file

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.

rails development environment circular dependency error

Last night I think I did something that hosed my rails development environment, and I'm unable to reverse what I did.
I migrated an update to production and was having some trouble precompiling a stylesheet so I backed out the changes and decided to attempt a precompile on my development machine.
Long story short, the precompile failed on my development machine (local) but when I tried to bring up my test system I got this error:
Sprockets::CircularDependencyError in Devise/sessions#new
/app/assets/stylesheets/application.css has already been required
I'm certain this has something to do with my attempted precompile, even though it failed because prior to that everything was working fine.
I tried to do precompile:clear because I read somewhere that will reverse/delete the precompile.
Am I missing something here? Does a precompile change configuration files somewhere that I need to manually reset?
This is rails 3.1 running on Ubuntu 11.10.
This is happening because your application.css.scss is most likely requiring a css file that's requiring application.css.scss. You'll want to go through app/assets/stylesheets and check the headers of application.css.scss, and then the headers of all the files it requires to make sure that none of them reference application.css.scss.
I fixed it by creating an application.css.scss and by importing each of my files in there, like this:
#import "backend.css.scss";
#import "frontend.css.scss";
then it worked

"require_tree argument must be a directory" rails 3.1.1 precompile assets

I've been round and round here with trying to get the assets to pre-compile on my production server (straightforward ubuntu install with ruby 1.9.2 and Rails 3.1.1, and tried 3.1.2RC with the new sprockets 2.10 as well).
"require_tree argument must be a directory". I've seen other issues related to this on stack but the situation isn't exactly the same and none of the proposed solutions have helped – like create a stub file in the sub folder, then reference only relatively at that point. No luck.
And to top it off, of course this works perfectly on all development machines (mac's but with identical configs, even matching gem for gem), in production env.
Here is my /app/assets/javascript/application.js:
//= require ../../views/app/manifest
//= require_self
Not much to it. Basically just pointing to the real manifest file for the app area (yeah, not exactly boxed vanilla Rails but...)
Here is my stub manifest in my views/admin (/views/app/manifest.coffee.js):
# = require ./app
# = require_tree ./models
# = require_directory ./views <- or using require_directory, either would work fine.
Like I said, in dev env, no issues at all. The asset pipeline compiles on the fly and everything is great. Running, rake assets:precompile on the dev machine, no issues either.
I send it up to the production machine and run the exact same code and I get:
require_tree argument must be a directory
There has to be some tiny tiny difference here that I'm just not seeing. Any help would be much appreciated!
I ran into this exact same issue you described. My production server was Heroku (cedar stack). In my case the issue was that one of my:
require_tree ./mobile
Was pointing to a legitimate directory, but this directory had no files. On dev it didn't matter but something about the production setup was resulting in the error, “require_tree argument must be a directory”.
Hopefully that helps.
require_tree must be given an existing folder, but git doesn't store empty folders,
therefore when you deploy on heroku, those empty folders doesn't exist.
one trick is to add an empty .keep file to the folders you want to keep.
For me, it worked to manually create an (empty) folder shared/vendor/javascript.

Rails 3.1: Sass Import from Lib

I've got a bunch of 'bootstrap' sass files I'd like to stick in my applications /lib directory, following the new conventions of the asset pipeline.
However, I need to import these into my application.css.scss rather than requiring them, as I would like to share some color variables etc. throughout the app. I have not been able to figure out a way to get #import to grab a .scss file from /lib/assets/stylesheets.
Any suggestions?
#import should look for any .css.scss files located in your assets load path, be it in app/assets/stylesheets, lib/assets/stylesheets, vendor/assets/stylesheets, or any additional paths added by gems, so it's odd that you're getting an error.
Note you do not need to pass a folder name when using #import unless the file is in a subdirectory of assets/stylesheets - sass-rails will look through every folder on your load path and see if the resource exists relative to those folders.
To ensure that lib/assets/stylesheets is in your assets load path (which it should be, since it's a default option) crack open a Rails prompt and type Rails.application.config.assets.paths. As an example, here's the result for one of my applications:
ruby-1.9.3-p0 :012 > Rails.application.config.assets.paths
=> ["/Users/tom/ruby/qa/app/assets/images",
"/Users/tom/ruby/qa/app/assets/javascripts",
"/Users/tom/ruby/qa/app/assets/stylesheets",
"/Users/tom/ruby/qa/lib/assets/stylesheets",
"/Users/tom/ruby/qa/vendor/assets/javascripts",
"/Users/tom/ruby/qa/vendor/assets/stylesheets",
"/Users/tom/.rvm/gems/ruby-1.9.3-p0/gems/jquery-rails-1.0.14/vendor/assets/javascripts",
"/Users/tom/.rvm/gems/ruby-1.9.3-p0/gems/bootstrap-sass-1.4.0/vendor/assets/javascripts",
"/Users/tom/.rvm/gems/ruby-1.9.3-p0/gems/bootstrap-sass-1.4.0/vendor/assets/stylesheets"]
It's also worth ensuring that sass-rails is up to date and running the latest version, since I believe early versions had limit support in terms of cross-folder #import.
N.B: I also believe that convention suggests files such as Bootstrap or jQuery should go in your vendor/assets folder rather than lib/assets
I had the same problem, and it was because i forgot restart server after add files to lib directory.

Resources