Aleks
Aleks

Reputation: 5380

Rails production server not using latest javascript file

I have a server where I have set nginx and Rails app. When I load page, my css and javascript links goes like this:

<link rel="stylesheet" media="all" href="/assets/application-01b482b5cbd306773ee4d7bc86b222a5d0c9b1c2dc82302957bc752dc079f6aa.css" data-turbolinks-track="true" />
<script src="/assets/application-cc1e40cfd63b56dd14a482241c0d44cc69c37206eeeb546d3f88ce94e09f8abc.js" data-turbolinks-track="true"></script>

The problem is when I load the page, I am always getting an error 404 Not Found for the javascript file /assets/application-cc1e40cfd63b56dd14a482241c0d44cc69c37206eeeb546d3f88ce94e09f8abc.js BUT curiously, not for css file.

Also, every time I change some of the javascript in the Rails and deploy the application (and therefore the javascrpt gets compiled,but the javascript fingerprint stays always the same!, where it should probably be changed).

My production.rb file looks like this:

Rails.application.configure do
  config.cache_classes = true
  config.eager_load = true
  config.consider_all_requests_local       = false
  config.action_controller.perform_caching = true
  config.serve_static_assets = false
  config.serve_static_files   = false
  config.assets.js_compressor = :uglifier
  config.assets.compile = true
  config.assets.digest = true
  config.assets.version = '1.0'
  config.assets.precompile =  ['*.js', '*.css', '*.css.erb']
end

And my nginx configuration file looks like this:

upstream rails {
  server localhost:3000;
  server 127.0.0.1:3000;
  server 127.0.0.1:3001;
  server 127.0.0.1:3002;
}
server {
  listen   80;
  server_name my_site.com www.my_site.com;

  root     /home/httpd/projects/my_site/current/public;
  index    index.html;

  location ~* ^/assets/ {
    add_header Last-Modified "";
    add_header ETag "";
    gzip_static off;
    expires max;
    add_header Cache-Control public;
  }

  location / {
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  Host $http_host;
    proxy_redirect  off;
    try_files /system/maintenance.html $uri $uri/index.html $uri.html @ruby;
  }

  location @ruby {
    proxy_pass http://rails;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
  }

}

And my /public/assets/ folder contains:

application-d211d1f163557c0f66d9380e7d485b799459ef763d25d832edc6c238dc502ac1.css
application-dd50fcd16cb3e12c063da05aa994afc5fe1558715e1af955cee8a633f5597171.js

(Where both version doesn't match the version in the generated html file, noted at the beginning of the question.)

I have tried clearing tmp folder, but it didn't help. Also, there doesn't seem to be nginx cache folder, so I haven't deleted it.

I am using capistrano for deployment.

What am I missing?

Edit (additional info for those who encounter the issue):

If you use capistrano for deployment, make sure you have app set for the roles for deployment, which if they if it isn't added to the roles, it will not invoke all required steps when running thin:restart / thin:start. In fact, it will run all the predefined commands, except the one which starts/restarts the server.

Also, if you are starting a server in production (in my case thin) and you receive a LoadError: incompatible library version then try to find a running server with lsof -wni tcp:3000 and kill the server. Then start the deployment again and it should work now.

Upvotes: 1

Views: 827

Answers (2)

Guillaume
Guillaume

Reputation: 1537

You should use the Gem uglifier

# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'

Then bundle install

Then rails assets:precompile

Upvotes: 0

Fire Lancer
Fire Lancer

Reputation: 30145

Rails in production mode uses a manifest file .sprockets-manifest-<checksum>.json (located by config.assets.prefix, public/assets/ is the default). This file along with the assets is generated by rails assets:precompile for Rails 5. Older versions have the same concept, but use rake and the filename may be slightly different.

The manifest is loaded by Rails when it starts in production mode and is used to determine the URLs to use for assets, such as with javascript_include_tag or image_path, Rails does not use or monitor the files in app/assets/ in production.

If you are having trouble with assets in production, make sure this manifest is present and refers to correct files (its a simple structure to read manually).

If it does, then make sure all Rails processes got restarted after the manifest was created/uploaded, because old processes will be using outdated assets. rails restart should do this, but depends on how you are running your processes.



Also its generally a good idea to leave all old asset files "online" for a short while when updating a live site as users that already loaded a page will have URLs for the old assets, but may not have actually downloaded them yet (in addition to if they were literally opening the page at that moment, things like images in collapsible sections, or CSS backgrounds for undisplayed classes may not have been initially downloaded).

Take even more care if hosting assets centrally on a static file store with multiple separate Rails servers, as while your restarting them some will be referring to old assets and some new.

Upvotes: 2

Related Questions