Skip to content

Instantly share code, notes, and snippets.

@eric1234
Last active April 9, 2021 02:09
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eric1234/5692456 to your computer and use it in GitHub Desktop.
Save eric1234/5692456 to your computer and use it in GitHub Desktop.
Generate non-digest versions of asset files for Rails 4 (similar to the way Rails 3 worked)

Purpose

Restores the generation of non-digest assets from Rails 3. This is essential for when those assets must be referenced outside of Rails. Maybe some of your app in in another language, or maybe some of your JavaScript is dynamically and conditionally loaded.

Usage

Compile your assets with the regular task:

rake assets:precompile

This appends the standard task so that after doing the normal compile it copies all the fingerprinted files to non-fingerprinted files restoring the behavior of Rails 3.

Installation

Place this file in lib/tasks/ (or any other directory where tasks are picked up).

# https://gist.github.com/eric1234/5692456
require 'fileutils'
desc "Create nondigest versions of all digest assets"
task "assets:precompile" do
fingerprint = /\-[0-9a-f]{64}\./
for file in Dir["public/assets/**/*"]
next unless file =~ fingerprint
nondigest = file.sub fingerprint, '.'
FileUtils.cp file, nondigest, verbose: true
end
end
@besquared
Copy link

This duplicates the manifest which causes errors. It needs to not copy the manifest

@besquared
Copy link

require 'fileutils'

desc "Create nondigest versions of all digest assets"
task "assets:precompile" do
  fingerprint = /\-[0-9a-f]{32}\./
  Dir["public/assets/**/*"].each do |file|
    next if file !~ fingerprint
    next if File.directory?(file)
    next if file.split(File::Separator).last =~ /^manifest/

    nondigest = file.sub fingerprint, '.'
    FileUtils.cp file, nondigest, verbose: true
  end
end

@erykwalder
Copy link

Was hitting issues on Heroku, since older assets are preserved for some time.

task "assets:precompile" do
  fingerprint = /\-[0-9a-f]{32}\./
  filemap = {}
  Dir["public/assets/**/*"].each do |file|
    next if file !~ fingerprint
    next if File.directory?(file)
    next if file.split(File::Separator).last =~ /^manifest/

    nondigest = file.sub fingerprint, '.'

    if filemap[nondigest]
      if File.mtime(file) > filemap[nondigest][:time]
        filemap[nondigest] = {file: file, time: File.mtime(file)}
      end
    else
      filemap[nondigest] = {file: file, time: File.mtime(file)}
    end
  end
  filemap.each do |nondigest, v|
    FileUtils.cp v[:file], nondigest, verbose: true
  end
end

Someone else might be able to come up with something a bit more elegant.

@tompave
Copy link

tompave commented Jan 20, 2014

This appends the standard task

... how?

@morefromalan
Copy link

Can you rely on appending the standard task? I thought rails did this for custom tasks but not necessarily builtins.

@etagwerker
Copy link

Thanks for sharing this! I did it this way:

Rake::Task["assets:precompile"].enhance do
  Rake::Task["nondigest:precompile"].invoke
end

task "nondigest:precompile" do
  fingerprint = /\-[0-9a-f]{64}\./
  filemap = {}
  Dir["public/assets/**/*"].each do |file|
    next if file !~ fingerprint
    next if File.directory?(file)

    nondigest = file.sub fingerprint, '.'

    if filemap[nondigest]
      if File.mtime(file) > filemap[nondigest][:time]
        filemap[nondigest] = {file: file, time: File.mtime(file)}
      end
    else
      filemap[nondigest] = {file: file, time: File.mtime(file)}
    end
  end
  filemap.each do |nondigest, v|
    FileUtils.cp v[:file], nondigest, verbose: true
  end
end

@jirihradil
Copy link

Hi, here is an updated version for longer assets names (64). The syntax taken from rails g task command. Thank you for the original code!

require 'fileutils'

namespace :nondigest do
  desc "Create nondigest versions of all digest assets"
  task precompile: :environment do

    fingerprint = /\-[0-9a-f]{64}\./
    Dir["public/assets/**/*"].each do |file|
      next if file !~ fingerprint
      next if File.directory?(file)
      next if file.split(File::Separator).last =~ /^manifest/

      nondigest = file.sub fingerprint, '.'
      FileUtils.cp file, nondigest, verbose: true
    end

  end

end

@k00ka
Copy link

k00ka commented Apr 9, 2021

Based on all of the good ideas above, I put this together. Quick 2-3 seconds to check for missing links, then 1/2 second to create each one. Should work well as long as you don't have a lot of change on each deploy. Good luck!

after "deploy:assets:precompile", "deploy:nondigest"

namespace :deploy do
  desc "Create nondigest versions of all digest assets"
  task :nondigest do
    warn "Creating nondigest versions..." 
    fingerprint = /\-[0-9a-f]{64}\./
    on roles(:web) do
      digests = capture("/usr/bin/find #{shared_path}/public/assets -type f")
      nondigests = capture("/usr/bin/find #{shared_path}/public/assets -type l").split("\n").map(&:chomp)
      digests.each_line do |digest|
        digest.chomp!
        next if digest !~ fingerprint
        next if digest.split(File::Separator).last =~ /^manifest/

        nondigest = digest.sub(fingerprint, '.')
        next if nondigests.include?(nondigest)
        execute("/bin/ln -sfr '#{digest}' '#{nondigest}'")
      end
    end
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment