Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Inability to compile nondigest and digest assets breaks compatibility with bad gems #49

Closed
gwcoffey opened this Issue · 180 comments

55 participants

Geoff Coffey Matthew Bass Rafael Mendonça França Guillermo Iguaran Ryan Angilly John Young Adrien will-r Ilya Katz Scott Schulthess Alex Speller Joost Baaij Michael Darmousseh Jeremy Kemper rubytastic Matteo Latini Chris Salzberg Alexey aldo sarmiento Ryan Bigg Rebecca Skinner Philip Andersen Adrian Macneil Jean-Louis Giordano and others
Geoff Coffey

For instance, the jquery_mobile-rails gem does not use image-url in its CSS. This is a bug really, but it "worked fine" in Rails 3. I assume they will fix the gem eventually. But in the meantime, in Rails 4, it is broken and as far as I can tell there's no way to work around it. The simple short term fix is to compile both digest and nondigest assets for this gem, but I don't see any way to do that. I can apparently only turn digest off or on globally for the application.

A rake assets:precompile:nondigest task or something similar would provide a workaround. But it seems to be gone now.

Is there a good way to deal with this, or do I just have to drop the gem and manage jquery mobile manually outside the asset pipeline, which is a pain?

Matthew Bass

+1

Removing generation of non-digest files also makes is impossible to have static 404 error pages that use the same images, JS, and CSS as the remainder of the site (without making duplicate non-digest copies of those files in /public). But then I end up with two copies of the same file in my app.

It's really unfortunate that this feature would be yanked without an explanation of how to deal with these situations.

Rafael Mendonça França
Owner

From the README: Only compiles digest filenames. Static non-digest assets should simply live in public/.

Matthew Bass

I saw that. So please explain how I'm supposed to reference my precompiled application.css file from my static 404 error page? Am I supposed to copy the precompiled file into /public and remove the fingerprint from the filename? So then, if I change the file in the future, I have to precompile, copy, and rename all over again? That's silly.

Guillermo Iguaran

You can use a rake task like this for your case:

task non_digested: :environment do
  assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
  regex = /(-{1}[a-z0-9]{32}*\.{1}){1}/
  assets.each do |file|
    next if File.directory?(file) || file !~ regex

    source = file.split('/')
    source.push(source.pop.gsub(regex, '.'))

    non_digested = File.join(source)
    FileUtils.cp(file, non_digested)
  end
end
Ryan Angilly

FWIW, I disagree with the resolution of this issue. I'm all for software being opinionated, but I shouldn't have to create a rake task like this in order to compile assets without the digest. It is my application after all ;) The bigger issue from my perspective is that this breaks applications on Heroku that are doing things like serving JS widgets that can't have digests in the name.

Ryan Angilly

https://gist.github.com/ryana/6049833

A monkeypatch for current version of Sprockets cc: @pelargir

John Young

I also disagree with the resolution of this issue:
"So please explain how I'm supposed to reference my precompiled application.css file from my static 404 error page?" is more or less the use case I have - a centralized Rails single-sign-on utility provides precompiled CSS via absolute URLS to other client applications.

Rafael Mendonça França

If you need to generate assets without digest so you have to do this on your own.

John Young

After talking this over, my big-chair developer decided to handle this by having Rails return a 301 redirect FROM the old, non-digested CSS location, TO whatever the latest digested CSS location is. That way, the client sites get to use a non-changing location and the rails app doesn't have to bake everything twice.

Rafael Mendonça França

This was exactly because we remove the undigest version. The Rails app had to bake the compilation twice.

Guillermo Iguaran

@tikaro like https://github.com/sikachu/sprockets-redirect (it's for Rails 3.x but should be easy to port to Rails 4)

Ryan Angilly

@tikaro clever, but you'll want to 302 instead of 301. 301s are permanent and some browsers will cache them.

John Young

@ryana good point, re: 302 and 301; I think I over-described what we've done, and may have gotten it wrong. Cloudfront is involved, too. Perhaps I can coax him in here so he can describe what he did.

Adrien

Hey guys,

Just wanted to say that I liked the middleware solution so I updated @sikachu's code for rails 4 : https://github.com/Intrepidd/sprockets-redirect

I'll issue a PR in no time.

Cheers

will-r

This seems like a real problem to me. It is now impossible to refer to rails-generated assets from outside the rails application. @Intrepidd's middleware is an elegant patch but sadly no use if you're delivering the assets through a CDN.

Would you accept a pull request that adds a config.assets.nondigest setting? There's no need to bake twice: we can just write duplicate files during Manifest#compile and remove them again during Manifest#remove. That's what I'm doing in a monkeypatch now and it seems to work well.

Ilya Katz

I concur, no having non-digest files without an alternatives is pretty annoying. Maybe I missed something, but what problem is it solving that non-digest files are no longer generated?

Ilya Katz

For those of you looking for a way to make it work with error pages, I adopted a post on how to make error pages come from asset pipeline (added the bit about non-digest assets) https://gist.github.com/ilyakatz/6346020

Scott Schulthess

I also have a use case for the ability to precompile assets without digests - we need to reference a javascript file from a 3rd party app, and it would be nice to use the asset pipeline - just without the digests!

Alex Speller

Agreed, @will-r it seems easy to not compile assets twice and still have this built in.

Joost Baaij

I know it's unproductive to pile on but I really agree with all the commenters here. A decision was made to remove this and by gosh we're gunna stick to that decision no matter what it seems. While the use case for non-digest assets is completely valid IMO:

  1. download almost any javascript library, like fancybox
  2. put jquery.fancybox.min.js in vendor/assets/javascripts
  3. put related images in vendor/assets/images
  4. include the main javascript in your application.js
  5. watch all your images not loading.

What are we supposed to do in this case? Put fancybox in public? So by-pass the asset pipeline altogether. This does not seem like an improvement to me, in fact it's a regression. We had something that worked just fine, now we are back to loading a bunch of javascripts separately. We can ditch the asset pipeline altogether?

If I am missing something, I sure would like to be educated. But putting potentially a dozen scripts in public is no kind of solution, frankly I am shocked it is even being suggested.

Alex Speller

Yeah I haven't yet seen a single rails 4 project that doesn't need to work around this. This decision should be reconsidered IMO.

Michael Darmousseh

This was a bad decision and is negatively affecting multiple apps i'm working on for no reason. Rails should not be this opinionated.

Ryan Angilly

@rafaelfranca you ever gonna come comment on this issue again? I've moved on by using the monkeypatch above, but I find it funny that I get emails from this thread every few days and you guys are just ignoring it. I understand you have jobs and probably busy, but you're stewards of this project. If you can't handle it, responding with a simple "ok cool submit a pull request and we'll merge it in" would suffice. I'm sure the community would pick up the slack.

will-r

This is what I'm using at the moment. It's a little crude and doesn't tackle the slightly harder problem of what files to remove, but as you can see the added computation is very slight. All we have to do is build another filename and write that file too.

module Sprockets
  class Manifest

    def compile(*args)
      unless environment
        raise Error, "manifest requires environment for compilation"
      end

      paths = environment.each_logical_path(*args).to_a +
        args.flatten.select { |fn| Pathname.new(fn).absolute? if fn.is_a?(String)}

      paths.each do |path|
        if asset = find_asset(path)
          files[asset.digest_path] = {
            'logical_path' => asset.logical_path,
            'mtime'        => asset.mtime.iso8601,
            'size'         => asset.bytesize,
            'digest'       => asset.digest
          }
          assets[asset.logical_path] = asset.digest_path

          target = File.join(dir, asset.digest_path)
          undigested_target = File.join(dir, asset.logical_path)

          if File.exist?(target)
            logger.debug "Skipping #{target}, already exists"
          else
            logger.info "Writing #{target}"
            asset.write_to target
            asset.write_to undigested_target
            asset.write_to "#{target}.gz" if asset.is_a?(BundledAsset)
            asset.write_to "#{undigested_target}.gz" if asset.is_a?(BundledAsset)
          end

          save
          asset
        end
      end

    end
  end
end
Alex Speller

Hot from the mines, there's now a gem for this:

https://github.com/alexspeller/non-stupid-digest-assets

gem 'non-stupid-digest-assets'

Problem solved.

Ryan Angilly

lol

Jeremy Kemper
Owner

We've had no trouble using digested assets throughout, and we've also updated our Rails 3 apps to do the same.

When an external app needs to reference a specific static asset, you can use a separate rake task that symlinks yourasset-<digest>.css to yourasset.css after precompile.

When you want to pull in an external lib that has its own scripts, images, and css, you can vendor the assets in public/somelib-v1/* an include the javascript in the asset pipeline. Then you're still free to put far-future expires on all static assets. When you upgrade to somelib v2, just add a public/somelib-v2/ directory.

Stable assets that can be publicly cached—and CDNed—forever. Now that's non-stupid :grin:

Michael Darmousseh

I don't have a problem using digested assets, but I do have a problem with rails being so opinionated about it and removing the choice. The biggest problem being with 3rd party javascript libraries or using my own app as a javascript source. Not every app is the same and that's why these choices need to exist.

rubytastic
  • This seems like a really bad Rails 4 default ( Forced default && No way out of it ) Please reconsider adding the old non digested versions back!
Matteo Latini

@turlockmike I have the exact same usecase you presented.

Joost Baaij

Hi @jeremy, I appreciate your explanation on how we are supposed to use external libs now. We've been forced to not use public for anything besides a favicon, so this is I think why you're seeing the pushback. Also, front ends web servers will not have been configured to serve from /public with optimal headers. And with the version numbers hardcoded in paths, some libs will require changes to the JS/CSS file every time you upgrade them. It's going to be a painful experience.

It would be incredibly helpful to have a writeup in the sprockets README or some kind of documentation how to use third-party libs. This issue is going to sting a lot more developers. It would be even better if we could come up with a formal, optimized approach on how to include the wide variety of libs we have in the wild.

Is anyone in this thread aware of a better solution? Personally I'm intrigued by the middleware that redirects to the correct asset. I just fear that doing this in rack middleware is a performance problem.

Joost Baaij

@alexspeller that works as long as you don't upgrade your lib or can live with possible breakage from cached assets.

Which is cool by me but arguably not the best solution we can think of.

rubytastic

If one would only need certain files to be non digested which seems the case many times ( you don't need all the files to be non digested and copied over an extra time ) how about an paramater added to image_tag like

= image_tag('/assets/logo2.png', :digested => false)

I tried this initialiser code hacked together below from several sources
but it fails on rails 4, this would be ideal solution for those of us who only want to make some files available

module ActionView
  module Helpers
    module AssetTagHelper

      def image_tag_with_digested(source, options={})
        digested = options.delete(:digested)
        digested = true if digested.nil?

        unless digested
          source = image_tag_without_digested(source, options)
          source.sub(/(\-[a-f0-9]+)\.(png|gif|jpg)"/, '.\2"').html_safe
        else
          image_tag_without_digested(source, options)
        end
      end
      alias_method_chain :image_tag, :digested
    end
  end
end
rubytastic

@alexspeller
Tried you gem for production but it failed to create any non digested files.

Alex Speller

@rubytastic I have tested it and it does create non-digested files. Please file an issue on the project and give more details if you can't get this to work.

Chris Salzberg

+1 I would also really like to see this reversed, as an option. for now using @alexspeller's gem, does the trick in a jiffy!

rubytastic

Confirm @alexspeller gem is working correctly. I had other local issues earlier on.

Alexey

gem 'non-stupid-digest-assets' convert only one css file, js files are not.
rails 4 + ruby 2.cap deploy

Alex Speller

@alexey please open an issue on the gem and give details https://github.com/alexspeller/non-stupid-digest-assets/issues

Alexey

@alexspeller
After investigation i found that its do create non digest files, but another gem (assets_sync) is not uploading them all.

thanks for nice gem

aldo sarmiento

@rafaelfranca seems to me like there are sensible and logically sound arguments against the change to sprockets. I believe a lot of people here are upset because you haven't addressed any of the comments objectively, but rather with a heavy-handed "just do what we say".

To recap arguments against non-digest to be included:

  1. Static pages (404s) will require you to create duplicate images (e.g. logos) from assets/images and put them into public/assets - that's a headache to remember later on down the road if you want to update images.
  2. Many people don't have control over css since they're using jQuery libraries that know nothing about the asset pipeline. Going into a plugin's css and changing url(..) to image-url("..") each time a library gets updated goes against Rails' philosophy of "web development that doesn't hurt".
  3. Some js libraries (like ckeditor) do tricky stuff like inject assets on the client side at runtime (ugly, but it's what it does)
  4. There hasn't been an explanation of why something so seemingly benign has been removed. So... why was this change so strongly supported?
Ryan Bigg
Collaborator

To address your points, @sarmiena:

  1. Reference static images from these pages. I do not know why you would precompiling images for these things. Stick them in public/images and be done with it.
  2. There are plenty of "bridging" gems out there for the major plugins and libraries. I would suggest you use those if you want to save yourself the hassle of find+replace operations.
  3. I don't know enough about how ckeditor works to fairly answer this point, but I think it's probably in a similar boat to point no. 2. There's probably a gem for it.
  4. That's one for the maintainers to answer.
aldo sarmiento

@radar
I can understand where you're coming from, but:
1) Having duplicate images in public/assets goes against DRY, which is at a higher level than rails opinions
2) In the event that plugins don't have gems, people shouldn't feel compelled to commit to maintaining a gem. That development hurts.
3) There are gems that do handle ckeditor. 2 in fact. However there is a huge community around it, and why should we mess with their tests to modify it for a gem?
4) Ditto

Ryan Bigg
Collaborator

I don't want to play this game any more. The asset pipeline clearly works for some people and also clearly does not work for other people. You seem to be someone in the latter group. Don't use the asset pipeline if it doesn't work for you.

aldo sarmiento

@radar sorry you took this as a game. i, and all those people above, just want to talk facts. this is important to rails core

Joost Baaij

Don't use the asset pipeline if it doesn't work for you.

Holy cow. That is just awesome advise, very professional! Thanks a lot, super helpful.

Ryan Bigg
Collaborator
Matteo Latini

LOL

Joost Baaij

That did make me smile though.

Matteo Latini

Anyone up for a game of sarcastaball? :smile:

Ryan Bigg
Collaborator

I don't see anyone being sarcastic here at all. All I see is a community agreeing on the implementation of a complex system and working together toward a common goal in complete harmony.

Matteo Latini

I know, it's just that the comments list is growing longer and longer and the best proposed "solution" is called non-stupid-digest-assets... It makes me smile :smile:

aldo sarmiento

@radar I think we are all for harmony and working towards a common goal. unfortunately, all voices have been pointing to why this change was a bad idea. I believe that saying things along the lines of "if you don't like the changes to something that you've all been using for a while, then don't use it anymore" is counterproductive to our community.

There is little harmony when core team supports features without addressing valid backlash & sound reasoning. It's nothing against Rails. I love Rails. But in OSS mistakes happen, and things get corrected. From all the reasons listed above, it sounds like a mistake happened when sprockets removed non md5 assets. That is, unless someone can counter these reasons effectively. :)

If there is something more productive we can do for the community regarding this matter, please feel free to let us know how we can contribute.

Michael Darmousseh

@radar For a lot of applications, this change makes absolute sense. Referencing a file which is cached by the browser/http does cause issues where a user might have an expired version of the asset but the cache header was not set appropriately.

For other applications, rails serves as a host for a set of javascript files which are used by third parties. In this case, given the impossibility of constantly asking users to update their script tags to reflect the new file hash, the best solution has been to have two copies of the file after compilation. One with the md5 hash and one without. If sprockets intends to support these types of applications, then I believe there should be an option to precompile an undigested version of the assets if desired.

It really comes down to the scope of the library and defining what it is for. If this gem is not meant to support certain types of applications out of the box, then it should probably be documented and rails should probably consider a replacement since i'm fairly certain rails would like to support those types of applications.

As far as third party javascript files like ckeditor or other javascript libraries which expect relative files to exist, perhaps a solution which allows you to pick files to be undigested using a whitelist would be the best solution. It would make it difficult enough that you would only whitelist files that you explicitly need to whitelist and asset pipeline can generally assume everything else is digested.

Alex Speller

@radar

  1. Reference static images from these pages. I do not know why you would precompiling images for these things. Stick them in public/images and be done with it.

Because static 404/500 pages almost always need to look the same as the rest of the site, i.e. sharing images, css and potentially javascript. Having to duplicate all of your sites assets for these pages is not a solution.

  1. There are plenty of "bridging" gems out there for the major plugins and libraries. I would suggest you use those if you want to save yourself the hassle of find+replace operations.

Forcing the use of bridging gems is a not a good long term solution to this issue. You should be able to use arbitrary javascript libraries with the rails asset pipeline.

  1. I don't know enough about how ckeditor works to fairly answer this point, but I think it's probably in a similar boat to point no. 2. There's probably a gem for it.

Same answer as (2)

The asset pipeline clearly works for some people and also clearly does not work for other people. You seem to be someone in the latter group. Don't use the asset pipeline if it doesn't work for you

It seems like it would be possible to greatly increase the number of people the asset pipeline works for by reverting this change, whilst at the same time not causing any negative consequences to others.

I know rubygems counts are not entirely accurate but my gem has received nearly 800 downloads in less than 3 weeks. It certainly seems like a lot of people have this problem.

aldo sarmiento

@alexspeller I can't speak for the other 799, but you got one from me! :)

rubytastic

Yes please listen to us developer, stepping back a little bit from your ( well deserved celebrity superman status )

Ryan Bigg
Collaborator

I only came onto this thread because @sarmiena was getting all caremad about it in the #rubyonrails channel (I ended up banning him because he was being aggressive and disruptive). I do not have enough experience to know which is the right way or the wrong way of dealing with assets, but I trust the people who are on the Rails Core Team more than random strangers espousing their opinions about The One True Way(tm) of developing an extension that they don't even help maintain. The Rails Core Team always has, in my experience, the best interests of the majority at heart. That is how Rails is still a popular framework.

Yes, I see a small minority of Rails developers are disagreeing with this decision. It's perfectly OK to disagree. To basically demand that a change gets done because you think it's wrong, is not OK. It is entitlement to the extreme.

Anyway, that itself is a whole other topic about the over-entitlement some people feel about open source software in general. You are not paying them to do any of this work; they are doing it out of the kindness of their hearts. You are not a maintainer of the project, so you do not get to help decide the direction of this project. If this project is going in a direction that you don't like, the "Fork" button is right there.

Even the LICENSE file itself says this:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT.

That "FITNESS FOR A PARTICULAR PURPOSE" is the part I would like to draw your attention to. If this gem is not fit for your particular purpose, fork it and modify it so it is. The maintainers of this copy of this gem have decided one direction to go, and so the project goes in that direction.

Option 1: Fork it if you do not like it.


Including the digest at the end of the filenames was done, as far as I know, because certain browsers (cough IE) aggressively cache files. If you have a file called, for example, your_application.js in your public/assets directory, and a user makes a request to a page which includes this asset, the browser will cache this asset. Same goes for any asset that comes from a gem that includes assets, such as ckeditor, or jquery-rails.

Later on, you deploy a new version of this asset to your server, which completely reworks everything, because that's what developers sometimes do.

The user requests the page that includes your_application.js again, but instead of the browser making the request to the server, it goes "I've cached this! I'm going to serve it from the cache.", because sometimes browsers are incredibly stupid. The browser doesn't know that you've reworked everything. The site breaks because the user's browser is still caching this non-digest-suffixed asset.

The way sprockets-rails works now (again, to the best of my knowledge) is that when the files are precompiled and placed into public/assets, they're given a filename that is suffixed with a SHA1 digest of their contents. This means that if a file changes in any way, it will be given a completely new name. Browsers have not yet learned that "your_application-abc123.js" is the same as "your_application-123abc.js" (and I hope they don't ever learn), so it's viewed as a completely new file by the browser, thus bypassing the excessive caching done by some browsers. In my personal opinion, it's a pretty smart idea. It's easier than debugging aggressive caching on outdated browsers, anyway.

This suffixing coupled with the asset-url and image-url helpers used in your asset files, is an effective means of working around the caching problems in those older browsers.


As for static pages that also depend on your assets, I have a potential solution in mind. You could store these files in another directory at the root of your application -- such as static_pages. In these pages, you could use the same helpers that you usually do within your application, like this:

<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>

A Rake task could then be used to process these files, correctly using the digest assets rather than the non-digest assets, and copy them over to the public directory.

This way, you don't need to worry about legacy browsers aggressively caching files and causing extremely-hard-to-debug problems on your users' computers, and you can still use the Rails-sponsored way of assets. You also don't have to worry about hacking sprockets-rails in ways that may break when sprockets-rails changes in non-trivial ways.

Option 2: Stop complaining and be part of the solution. Build this Rake task and provide it as a gem so that people can use it if they wish.

aldo sarmiento

@radar I am somewhat perturbed by your need to make this personal and referencing something in IRC that has no significance in this thread, not to mention that it is also a distraction from the issue at hand. To suggest "caremad" means not willing to use logic. As you can see above, I'm only using logic and NOT demanding anything to be changed. This is supposed to be a forum for progress and constructive discussion. I would appreciate it if you would do your part to keep professional here, especially since you are a valued member of the rails community.

As previously stated, there were valid scenarios that appeared to outweigh the decision to remove this functionality from sprockets. If we're wrong, we just want to know why.

I'm willing to say that @radar's last response is a strong enough argument. That's all that was needed to be said from the start.

Ryan Bigg
Collaborator

@sarmiena I love the way that you completely ignored the last 2/3rds of my post. :clap:

Ryan Bigg
Collaborator

You are wrong because a) the Rails core team says you're wrong and b) I proved conclusively in the part of my post that you did not read that digestable assets are absolutely required due to the bad behaviour on the part of ancient browsers.

At the end I even proposed a solution to this problem, which by you not commenting on at all proves that you did not read the entire thing.

Ryan Bigg
Collaborator

I've said everything that I want to say in this thread. I will no longer be participating.

Alex Speller

@radar you have made a convincing argument. Personal insults are not necessary.

Rafael Mendonça França
Owner

TL;DR yes, we choose what we think is best for the direction of the project. And the reasons is here in @radar's comment and @jeremy's comment.

We never said this gem have to solve every problem in the world, and we don't think it should. If you have a different problem that is not solved by this gem, it is your job to solve your problem. And we already give you a lot of suggestion in this thread about how to solve some problems you may have.

The majority of Rails applications don't need non-digest assets and we don't want to keep this code in the gem since it will not used by the majority of our users. It is all about maintenance cost.

Rafael Mendonça França
Owner

TL;DR 2, this rake task would solve almost all your problems: #49 (comment)

Ryan Angilly

Well that escalated quickly. Must have been one hell of an IRC exchange to get people this heated :) I would encourage everyone to set a calendar reminder for like a month from now and come back and re-read this whole thread noting the timestamps. There are probably some valuable lessons to be learned in how to better manage this from all sides in the future. I'll certainly be thinking about it.

Give that this is not going to make it's way in sprockets, a summary of available options:

Happy hacking ;)

Guillermo Iguaran

TL;DR: Digests are used for cache busting. Remember that if you use the non-digest assets and serve them with far-future expires headers, you will cause problems with cached assets if the contents ever need to change.

Rails embraces good defaults and in my book that doesn't count as a good default.

Anyway Rails is not stopping you if you want to re-add it using third party gems (like the gems suggested in this thread) or add a custom rake task to your app (as the custom task suggested in this thread).

Ryan Bigg
Collaborator

@ryana It was six days of this discussion. http://logs.ryanbigg.com/p/sarmiena_

aldo sarmiento

@radar if I recall, you were no longer contributing? I appreciated the fact that you removed your comments on this thread where you were personally attacking me... however, your out-of-context and single sided logs of my IRC conversations are not appreciated. If you wanted to show the real story, you'd put the entire conversation on there. But I don't think you have it in you.

Also it was definitely not SIX days of asset-digest conversation. It was a couple days of asking if anyone was having performance issues with precompile due to deploy problems I was running into. The first time i mentioned this thread was last night.

Lastly, I can't believe you're still poking at this subject to try to bash me. Seriously? This conversation should have been over once everyone understood the facts and agreed. You're just being spiteful and tedious for no reason. There was a point in time when I had respect for you, but this is really disappointing.

Ryan Bigg
Collaborator

@sarmiena Anyone can click on any part of the logs and see the full context of the messages if they wish. Six days you went on about how the asset pipeline was broken. Starting here, on the 3rd of October: http://logs.ryanbigg.com/RubyOnRails?date=2013-10-03#1322292. It finished yesterday (the 9th) when I banned you for being aggressive and disruptive to the whole channel. 9-3 = 6.

I actually regret deleting my comment about you being an entitled brat because it appears (to me, at least) that's all you're doing at the moment. You're not helping to fix anything. Just bitching because the project is broken in your particular circumstance.

Enough. I am putting a mute filter on this thread in Gmail and blocking you on GitHub.

Have a nice life.

aldo sarmiento

Wow you're really a power drunk mod. For the record I was banned w/o warning for asking questions. It's not my fault @radar didn't like the questions. I encourage anyone to look at those logs and see that I actually do help people in the channel AND of course I'm going to get upset when someone starts pushing me around.

This is just ridiculous.

Rebecca Skinner

oh man, I went through the logs and saw the exact same argument I had with @sarmiena was actually on the 7th. That's awesome.

Philip Andersen

I have, what might be a related issue.

I have a Sass file which references som SVG-images. All the SVG images are getting a hash appended to the file (as expected) when precompiling. The issue arises, since the compiled CSS file is referencing the file without the hash.
Shouldn't the Sass compiler use the digest version of the images, which are referenced in the sass file, or should I e.g. use the gem https://github.com/alexspeller/non-stupid-digest-assets, to create two versions?

Jean-Louis Giordano

+1 on the issue, although I don't think the title is appropriate. I'm coming here from https://github.com/alexspeller/non-stupid-digest-assets

We're building an API and chose to prefix our assets with a version number (i.e v2/my_asset.js). This was working fine with Rails 3 but is broken in Rails 4 because non-digest versions are no longer generated.

I feel that generating both digest and non-digest versions of the assets should be straightforward and cost very little work or maintenance, if that is the case would you please reconsider your decision? I know too little about the codebase to do a PR myself.

Geoff Coffey
Jean-Louis Giordano

@gwcoffey like I'm saying, we're building an API and what we compile is a javascript and CSS which is used OUTSIDE our application. We absolutely need non-digest assets, because the clients that use our javascript are not in our control.

The version you see in the link is the version of our API, not the version of the asset.

Jean-Louis Giordano

@gwcoffey now that I'm re-ready my comment, I see how my message might have been confusing :p sorry about that

Nicholas Johnson

Oh hey there, I'm a little late to the party here. It should probably be possible to have the option to expose non-digest assets as well as the digest versions via a config setting. I need to refer to assets externally, as I have several syndicated JavaScript widgets. I'd be happy to submit a patch if other people agree :)

Ryan Angilly

@forwardadvance I think several dozen people agree, but unfortunately not the gatekeepers. Their advice is to fork sprockets and maintain your own distribution of it. There is a list of available options in this comment above: #49 (comment)

Have a good one!

igravious

Hi there Rails Core Team. This just bit me. You got this one wrong.
I find it hard to see how this wouldn't affect any decent sized project to be honest.

I use two different JQuery plugins. Both have CSS and use images.

In development mode, no problem. Images from vendor/assets/stylesheets/images work

In production mode, they get digested (once you learn the magic config.assets.precompile += %w[*.png *.jpg *.jpeg *.gif] incantation).

This places them in public/assets/images which is the right place but they are now fingerprinted so the CSS references break.

It is not an option to use image_tag because these are 3rd party libs and it's a royal pain.
It is not an option to copy them to public/images because that's not really where they should be living.

Either we need a way to
a) selectively copy over these types of assets without digests
or
b) ???

There's no way this issue should be closed.

Rebecca Skinner

The solution AFAIK has always been to modify the plugins to update the asset references. It's a bit annoying, but it works fine.

Geoff Coffey
Geoff Coffey
Andrew Kaspick

I was under the assumption that all 3rd party libs should go into vendor/assets (that's been what we've been "told" to do since rails 3... I thought).

Since I'm trying to follow "conventions" (which are now different?), I've got everything working in vendor/assets with one extra addition... needing to do the following...

config.assets.precompile += %w(third_party.css {whatever}/*.png)

Is the recommended approach now to move 3rd party libs that we've made "pipeline ready" back into app/assets?

Geoff Coffey
Stefan Hendriks

+1 for this issue. Wanted to make my 404/500/422 pages look the same as in the rest of the app. We use custom fonts and our app uses haml/sass everywhere. Some issues are fixed by using the asset-path within our sass/haml which is fine. However, I still need to reference from my static page to the end result (with digest).

I have put the files now in my rails app and let exceptions route through it.

Andrew Kaspick

@stefanhendriks Put non-digested files in your public dir. If you need the special casing for your static pages, then that's where you should put them. Otherwise there are the other proposed gems/options provided in this discussion that should help.

Stefan Hendriks

@akaspick Actually I am using now dynamic pages and it works fine. The only remaining problem I have now is rspec complaining about missing templates once a 404 or a 500 error occurs. Even though I set config.consider_all_requests_local = false within test.rb.

Any idea? generating static versions of them (as Ryan does in his screencast) works (as the template exists again, and the test is passing), but the whole point is to do dynamic pages, so this solution is not sufficient.

Ryan Bennick

Over the past year it seems that front-end libraries have been rapidly adopting the bower package manger. For may reasons bower is awesome. Mainly because it is similar to ruby's gem system. You can configure bower to install packages directly into the pipeline. Updating packages just takes altering a bower.json file and running bower install. Front end dependency life is just grand.

This change to sprockets-rails makes any images these bower installed packages use unfindable because they reply on non digested relative paths. Updating the packages directly just wrong and using a gem wrapper is, imo, a way of the past.

I will be using the rake task listed above but it would be nice if sprockets-rails could support this common scenario. As others have suggested having the ability to whitelist files or directories to keep non-digest assets, like a config.assets.nondigest option, would solve this.

Just some thoughts. Thanks to those who contribute to this project. I appreciate it.

Chris Salzberg

Completely agree with @bennick and strongly recommend having a look at using bower for managing front-end assets. I wrote this blog post on using bower with rails that might be useful to some people interested in doing that.

Gabe Kopley

+1 that this issue ought to be reopened.

Guillermo Iguaran

@alexspeller what if I rename my rake task to assets:precompile?

namespace :assets do
  task :precompile => :environment do
    assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
    regex = /(-{1}[a-z0-9]{32}*\.{1}){1}/
    assets.each do |file|
      next if File.directory?(file) || file !~ regex

      source = file.split('/')
      source.push(source.pop.gsub(regex, '.'))

      non_digested = File.join(source)
      FileUtils.cp(file, non_digested)
    end
  end
end

Then your argument about not working with heroku/capistrano, etc aren't valid anymore

TestingBot

Thanks for the gem @alexspeller

Alexey Chernenkov

+100500

breadnotes

I have the same use case others have mentioned with error pages that are broken with the removal of non digest assets.

TheR2

Just started to convert my applications and stumbled on this problem too. So I thought I could put my 2 cents on problem.

We have this wonderfull mechanism of ruby gems, to include external ruby code in our projects and use them as engines in rails applications. But world is moving to more and more code being written in javascript and with this sprockets move it has become even harder to include third party javascript code transparently in our projects.

Moving static javascript to public folder, for using projects like ck_editor, is probaly OK if you use library only for your own, single project. But what if same code is beeing used by multiple projects. Than copying same code all over again becomes pain. That's why gems were invented for. Problem is that gems don't handle putting external javascript code into right destination directory. But sprockets know everything about it.

Funny thing is that code placed into assets folder works perfectly OK when in development, but in production and test nothing works at all, because the code doesn't get copied to destination folders.

I was already suggesting new directive eg. 'copy_directory' which would copy everything what is found in that directory to /assets/diretory when assets:precompile is run. This would help us a lot to gemify third party javascript libraries and include them into rails projects.

Or have I missed something that is already build into rails?

by
TheR

Alex Speller

@TheR2 gems work fine with the asset pipeline. However rubygems are not the best solution for packaging javascript libraries. Have a look into bower and bower-rails for packaging javascript libraries, they work quite well together.

Reto Schüttel retoo referenced this issue in rails/rails
Closed

Cant disable asset digests #10810

Michael Amor Righi

@guilleiguaran Thanks for the Rakefile solution, but unfortunately I found a problem with it after using it for a few days.

If you keep old copies of files in public/assets (the default behavior in Rails 4, even after an asset:clean) then you risk having old versions of your assets ending up in the non-digest files.

For example, imagine on Monday assets/javascripts/application.js compiles to public/assets/application-39f56e9c8b27cc62488e84f9f5cf7788.js, and after making changes on Tuesday it compiles to public/assets/application-1274e865b362e15aa2a29b1c9dbdf025.js. During precompile, both application-39f56e9c8b27cc62488e84f9f5cf7788.js and application-1274e865b362e15aa2a29b1c9dbdf025.js will get copied to application.js, with one clobbering the other. If you're lucky, the most recent file will be the one that wins. I wasn't so lucky today in a production environment. :-)

I switched to using https://github.com/alexspeller/non-stupid-digest-assets and that's working better for me.

Alexey Chernenkov

@righi @guilleiguaran I faced with that problem too. non-stupid-digest-assets gem helps with it.

Reginaldo Junior

+1, I'm using the provided rake task to solve the problem, but it should be a Rails default, this is a pain specially for beginners where things should work smoothly by default, it's the Rails philosophy.

If you do not want non-digested files to be generated you should config not to generate them, instead of forcing the rest of us to do the opposite, since we are like 99% of the cases.

abarnet

I think it's a good default not to generate non-digest because non-digest requires doubling the number of files written. However, there should be a config option to either generate all non-digest or s subset of non-digest files.

I think for a lot of people (myself included), there are a few files like generating error pages that need non-digest versions but all the rest get served via digest assets.

Reginaldo Junior

Everybody I know uses some files that references non-digested assets. I should not force the front-end developers of my project to always use rails helpers in their layouts to reference correctly digested assets, this violates Rails convention over configuration pattern.

There was no single project in rails 4( even my coming soon page) where this was not an issue.

Keith Gaddis

+1 on Rails core getting this wrong and not providing an officially supported route (via config option or official rake task) for remediating the problems caused by their heavy-handedness.

Will Glynn

+1. This needs to be a config option.

Bill Lipa

Another use case to consider is HTML emails. There may be many emails sitting in people's mail readers that were sent before this change was made. Those emails probably use non-digested asset references because they were the stable choice for long lived documents, if you're willing to commit to not deleting or changing the assets. It's impossible to go back and change these emails because they were already sent.

I appreciate the hard-core digest only default, but I'd like to be able to make a hand tuned exception for certain assets.

Brian Jordan

+1. Also bit by the use case @wlipa mentioned.

Alan Graham

+1 Also here just to complain. Seems very short-sighted to assume all 3rd-party assets will use the Rails pipeline hooks like 'asset-url' when referencing images/fonts. Why not just provide both?

Please make a config option so 'non-stupid-digest-assets' is not basically a requirement for anyone building a Rails 4 app.

Celso Dantas

Question for the team: How can you build a JS API with Rails 4? It doesn't seem possible without generating a non-digested version of the file.

Alex Speller

@celsodantas I think you are confusing the asset pipeline with json responses to controller actions. Nothing in this discussion is relevant to building APIs.

Celso Dantas

I'm not talking about controllers responding to JSON, I'm talking about writing JS code to publish to clients of my application to use (like a SDK). In these case we need to give the clients a fixed path.

Example: http://docs.shopify.com/embedded-app-sdk/initialization

Alex Speller

@celsodantas oh, I see what you mean. The techniques to achieve this are discussed in great detail above.

Celso Dantas

@alexspeller, I saw the "solutions"/workaround. I just think it's not a wise idea to not add an option to add the non digested files back.

Ryan Angilly

I find it "ironical" that this issue just bit me again 8 months after I first expressed my opinion that this should be changed.

I'm using one of Symbolset's awesome font icon sets: https://symbolset.com/icons/gizmo

I copied their webfonts and CSS into my assets directory. Here is a segment of the stylesheet that accompanies the font:

stylesheets/ss-social.css:15:  src: url('/assets/webfonts/ss-social-circle.eot');
stylesheets/ss-social.css:16:  src: url('/assets/webfonts/ss-social-circle.eot?#iefix') format('embedded-opentype'),
stylesheets/ss-social.css:17:       url('/assets/webfonts/ss-social-circle.woff') format('woff'),
stylesheets/ss-social.css:18:       url('/assets/webfonts/ss-social-circle.ttf') format('truetype'),
stylesheets/ss-social.css:19:       url('/assets/webfonts/ss-social-circle.svg#SSSocialCircle') format('svg');

ss-social.css is then imported into my application.css.scss. Now, it's a pretty safe bet these assets are never going to change. But sure enough, after upgrading to Rails4, all my social icons go bye bye because the ss-social-circle.(eot|woff|ttf|svg) files no longer exist in my asset directory.

I know how to fix this. I think we are saying that the best practice here is to go into ss-social.css and change the call from url() to asset-url(). Ok. That's fixes it. Ignoring the fact it's annoying to have to do that an already minified CSS file (which this isn't, but others are), it does solve the problem.

But that's not what concerns me here. What concerns me here is that we've now built something into Rails that by default works correctly in the development environment and breaks in the production environment, and there is literally no way you would know it until you run the app in the production environment.

This doesn't just happen on Heroku btw. It also happens on dokku/docker since the assets directory starts fresh every time a container is started. On deploys directly to a linux box (via Capistrano et al), these issues may be hidden if the assets directory is old and still contains non-digested assets from before this change was instituted.

What's maybe even worse is that this default also works in the test environment, so if you're going out of your way to generate screenshots in Poltergeist to ensure stuff looks good, you're still going to get bit once you go to production.

Opinions about caching best practices and performance aside, I think we can all agree that having a default that introduces an error when going from dev -> production is not something that can stand.

I think the cleanest way to address this is to take all the assets generated by the asset compilation (with their digests) and simply make copies of them without digests in the name. We don't need to recompile. The copied files will still contain references to digested assets, but that's ok I think. This should be the default behavior.

If you're a contributor on this project, please let me know if you'd accept a pull request of this nature.

Thanks for reading this whole thing!

Ryan Bennick

@ryana I agree the default should be to have non digest assets with an option to exclude them. To me this change feels like a big case of premature optimization.

Keith Gaddis

@ryana @bennick It doesn't bother me that the default is for digested assets. I think convention over configuration is perhaps Rails greatest contribution to the web development zeitgeist, and if most people need digests only, great, I have no problem making a slight modification to my environment settings upon upgrade.

What I find incredibly irksome, heavy-handed, and a bit arrogant is that the maintainers of the gem have determined that they know what's better for my use-case than I do, and that there is in fact no reason for me to have an officially supported method of generating non-digested assets. The hacks detailed in this thread are just that: hacks. If it works, and its apparently easy enough to do that nobody on the maintenance team feels the least bit troubled by requiring everyone in this thread (realizing that the commenters are likely the tip of the iceberg) to use them, then why such resistance to adding it as an officially supported option so that we have an interface we can rely on in future versions of the framework? This isn't merely a matter of a vocal minority clamoring for a feature no one needs. This is a feature which was official, and as such relied upon, by many people, and its summary removal (without even a deprecation process, AFAICT—correct me if i'm wrong) was absolutely the wrong move, and I'm flabbergasted at the resistance to adding it back when there's zero impact to anyone else.

Geoff Coffey
Ryan Angilly

@gwcoffey yeah good points. I would support a solution that made this not work in development. Of course, that would probably break a lot more applications :)

Perhaps we make the asset pipeline throw an error saying "Hey man you need to use asset-url() here" when it encounters a "url()" call to a relative path in an asset directory, that might be the right way to handle this.

Ryan Bennick

@ryana A problem with that approach, as discussed above, is that you should not be modifying 3rd party front end libraries. These libraries also conflict with @gwcoffey idea of putting assets into public unless you are will to store all of your 3rd part library code directly in public. This, however, defeats much of the purpose of using the asset pipeline.

Alan Graham

@bennick I was just typing exactly this. Everytime I update twitter boostrap in my app I have to go and find/replace asset-url everywhere. This can't be the right way going forward.

Rafael Mendonça França

unless you are will to store all of your 3rd part library code directly in public. This, however, defeats much of the purpose of using the asset pipeline.

Generating assets without digest also defeats much of the purpose of using assets pipeline. I don't think you guys remember but we generate assets with digest because assets without digests are cacheable and you don't control the asset expiration.

Alan Graham

And I know someone will say "use the asset gem", but that requires the JS maintainers, or someone else, to create and maintain that gem (separate from a Bower package which usually already exists). Seems unnecessary to require a rails port for all JS packages that use fonts/images/etc.

Ryan Angilly

@rafaelfranca that's fine, but the fact still remains that in the current setup, something can work in development that will break in production. are you suggesting that's acceptable?

EDIT: typos.

Rafael Mendonça França

No, I'm not. About this subject (matching development and production behavior) we have #117, which is open, so we agree it is a problem and we already started to work to fix this (see #84 and #96).

About generating non-digest assets my opinions remains: who need to do this, do with one of the solutions already explained here.

Gabe Kopley

@rafaelfranca asset pipeline gives you automatic coffeescript compilation of your embedded javascript SDK. I'm not arguing we should support the embedded javascript SDK use case 1st-class in rails (by default configuration), but why not support it as 2nd-class (by config option), rather than 3rd-class (rake task or gem)? I don't understand who loses if we implement the config option compromise?

Ryan Angilly

@rafaelfranca Ok great. I like #117, but it's not obvious from reading that issue that you agree it's a problem. Thanks for pointing that out and clarifying.

So back to my example with the symbolset font/CSS. What do you propose there? Are you saying in that case, the best practice is that if I want something in the asset pipeline, I need to go through any imported CSS files and replace "url()" with "asset-url()" ?

And by the way dude, thanks for all the work you do here. It's hard not to come off as adversarial in these comment threads. I know I'm probably coming off that way due to my curtness. I don't mean to. I'm just trying to drive through to resolution on something I believe needs fixing.

Rafael Mendonça França

I must make clear that I understand your problems, but right now we don't have a good solution that will fix both problems.

If we start to generate undigest files we will fix the problem of people changing 3rd party code to make it work with assets pipeline but we will have reports of people changing their assets but users not receiving these changes.

What I do now, in my projects, is put 3rb party code in the public directory or override only what I need (CSS make this possible to you). So instead of opening the bootstrap library and changing it to use asset-url I only add a file assets/stylesheets/overrides/bootsrap.css.scss with this line:

.some-image {
  background: asset-url(foo.jpg)
}

Of course, this is not the ideal but works right now (and you don't need to change people library).

I promise this problem is not forgotten and we are trying to find a solution that will fix both issues (it is planned to Rails 4.2).

Until, the solution is not implemented, I recommend to use one of the solutions already presented on this issue.

Gabe Kopley

Thanks Rafael, very thoughtful response. :beers:

Ryan Angilly

Ok @rafaelfranca thank you. That's a great response for my specific issue. I'll utilize overrides for now. In the meantime, I think #117 is a good direction to go in.

While I have your attention, there is one more use case that I want to make sure gets consideration while you figure out the fix for Rails 4.2:

http://tallybits.com is a project I worked on throughout last year. In that project, we generate a JS tag for people to embed in their application. The underlying JS (https://www.tallybits.com/assets/tally.v1.js) is written as tally.v1.js.coffee.erb and is compiled by the asset pipeline. To address this lack of a non-digested asset, I rewrote the asset:precompile task to remove the digests from filenames after compiling. As you pointed out, this introduces the issue where new versions of the JS are not picked up because of the cache headers.

I propose a configuration option along these lines:

config.assets.private_assets = ['tally.v1.js'];

This config option would be used in two ways. First, it would take tally.v1.js and prevent a digest from being appended to it. Second, it would instruct Sprockets to omit the Cache-Control header, and rely on the Etag for assets in that list.

Just an idea. If you'd like, I would enjoy contributing something like this for Rails 4.2. Just let me know.

Thanks again for responding today.

EDIT: Calling the config option private_assets was just me being lazy. There's probably a better name for the option.

Rafael Mendonça França

Thank you for the suggestion but this is one of the cases that I think don't belongs to Rails. Of course you are not the only one that have this problem, but this is not the common workflow that the majority of people will use.

You may say: this is just one new configuration and some new code. But every code path we add to this gem is more code to us maintain. And since we don't have your problem I'm pretty sure this behavior will break in a release, and we will have to deal with the bug reports, withe the fix and with the release process ourselves, even if we don't use that code.

You may say: but this is your job. Well that is true, but it is a voluntary job, and I only do this because I enjoy this job. But, it is easy to burn out and leave the job because the majority of users we deal are users complaining about something broken or they don't agree. So to keep my job enjoyable I prefer to maintain things that I use every day, that make my day job easy.

This is the main reason I'm reluctant to add any new feature to Rails or related projects, until I see usage on my day job.

I'm sure this is the case for every member of the Rails Core team.

Your feature can be useful for us in future but right now I prefer to keep it out of this project and suggest you to write a new gem that will be useful to people with the same problem than you.

I'll discuss your suggestion with the Core Team to see if anyone has this same problem than you but I think this is the only thing we can do now.

Ryan Angilly

Understandable. Thanks again for the response. I'll look into writing a gem that does what I'm talking about, and I'll reach back out when it's worth taking a look at.

Thanks again!

Arthur Nogueira Neves
Collaborator

@ryana We had this discussion internally as well, as at Shopify we provide a js SDK to dev so they can import on their stores. Anyways, we solve this in a really simple way. I will post a gist here showing what we did. https://gist.github.com/arthurnn/9677780 (code from @celsodantas )

Ryan Angilly

Oh cool @arthurnn thanks for the gist (and @celsodantas for the code). One thing to keep in mind with your solution is that you're still sending back a Cache-Control: public, max-age=3600 header with that request, so different versions of your app.js will exist in the wild for up to an hour. While that's probably a completely acceptable solution for what you guys are doing, it might not be for others.

ra:app(master) ryan$ curl -I https://cdn.shopify.com/s/assets/external/app.js
HTTP/1.1 200 OK
Date: Fri, 21 Mar 2014 12:50:25 GMT
Server: cache-c32-CHI
last-modified: Wed, 19 Mar 2014 21:24:27 GMT
etag: "e9ea0b513ca0d1a51f43c1d180ea6a04"
content-type: application/javascript
X-Request-Id: 12e6cdb8f66cf31a94998031be7b8380
Link: <http://cdn.shopify.com/s/assets/external/app.js>; rel="canonical"
Content-Length: 15818
Accept-Ranges: bytes
Cache-Control: public, max-age=3600
Access-Control-Allow-Origin: *
X-Served-By: cache-v37-ASH, cache-c32-CHI
X-Cache: HIT, MISS
X-Cache-Hits: 1, 0
X-Timer: S1395406225.309598923,VS0,VS475,VE476,VE17
Vary: Accept-Encoding
Adrian Macneil

Let's not pretend this is adding a new feature. It's restoring an extremely useful feature which was removed for overly idealistic reasons. I can't believe I've been following this thread for months now, and you guys still haven't reached a solution, other than using the non-stupid-digest-assets gem. Almost everyone on this thread except for the core team needs this feature. I'm amazed that you say you haven't run into this in your day job, given that every site with HTML emails, or static 404 pages has this problem. How do you reference images in emails, or use CSS in static pages with the default functionality?

Seriously, sort it out guys. The asset pipeline has more uses than just digesting assets, and it should be up to developers to weigh up the trade offs of using non-digested URLs (especially given that rails doesn't even concern itself with asset cache headers by default). Having digest-only by default is one thing, but making something impossible is quite another.

Rafael Mendonça França

It is not impossible, there are a lot of way to archive it and the easiest doesn't even require adding any gem.

task non_digested: :environment do
  assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
  regex = /(-{1}[a-z0-9]{32}*\.{1}){1}/
  assets.each do |file|
    next if File.directory?(file) || file !~ regex

    source = file.split('/')
    source.push(source.pop.gsub(regex, '.'))

    non_digested = File.join(source)
    FileUtils.cp(file, non_digested)
  end
end
Adrian Macneil

Ok, but if it's that easy, why can't you just include that as an option? Isn't the rails way to eliminate boilerplate code for common tasks, rather than encouraging people to copy paste blocks of code into every new project?

Rafael Mendonça França

Because we will have to maintain a feature that we know it is broken. How would you fix the cache problem?

will-r

I suggest that you manage expectations by making the cache problem explicit.

asset-url(foo.jpg, caching: false)

It becomes the developer's problem, not yours.

Adrian Macneil

How would you fix the cache problem?

The cache 'problem' is not a problem. It's a trade off, and should be presented as such to the developer (and I'm all for leaving it disabled by default btw). Putting assets under /public doesn't solve the cache problem, and neither does your rake task. However, in the vast majority of uses cases (static 404 pages and the like), caching isn't a huge issue (I don't care if a handful of users get slightly out of date css on a 404 page or an old logo in an HTML email for a few days).

The main problem I see is that you are treating asset digests as fundamental to the asset pipeline, whereas in reality that is only one of many features of sprockets (and therefore something I may wish to disable in certain situations). The asset pipeline has many other uses (which it is fantastic at), such as compiling sass, coffeescript, and combining and minifying different types of files in a single, consistent way. Sometimes I only want those features, and not digests. By saying "just put it in /public", you are neglecting all the other awesome things which sprockets can do for me, all because I don't want one particular feature.

You may say: but this is your job. Well that is true, but it is a voluntary job, and I only do this because I enjoy this job. But, it is easy to burn out and leave the job because the majority of users we deal are users complaining about something broken or they don't agree. So to keep my job enjoyable I prefer to maintain things that I use every day, that make my day job easy.

I'm well aware of this and it's unfortunate that most of the time you hear from users is only when they are unhappy. At the same time though, when you take on maintaining a project used by a huge number of developers worldwide, you need to be considerate of their needs, and not just your own. Comments such as "Fork it if you do not like it" above (and I realise it wasn't yours) only come off as rude and obnoxious.

I'd really love to see this feature restored in a future version of rails. If it's not, I will survive, using rake tasks pasted off the internet, or more likely the non-stupid digest gem. However, it makes me sad how many people have taken time out of their day to express their concerns on this thread, and how it mostly seems to be falling on deaf ears.

Nicholas Johnson

I totally agree with this:

asset-url(foo.jpg, caching: false)

Again, I'm totally happy to write it and submit a patch if that would be acceptable.

Most of the time digest urls are awesome, the exception being when I want to give a URL to someone else, e.g. an HTML email which may be opened later, a piece of JavaScript I want someone to embed on their site, or a static page.

Rafael Mendonça França

However, it makes me sad how many people have taken time out of their day to express their concerns on this thread, and how it mostly seems to be falling on deaf ears.

Lets take a constructive path here, since only discussing this will take forever and no problem will be solved.

To alleviate users having this problem right now, lets create a optional rake task to generate non-digest assets.

To alleviate the cache problem/trade off, lets document it in our assets pipeline guide.

Does this work for you guys?

I'm really busy these days with the release of Rails 4.1 and some problem related with sass 3.3, so if anyone want to open pull requests I'll gladly review.

I suggest that you manage expectations by making the cache problem explicit.

asset-url(foo.jpg, caching: false)

I'm not sure about this, but this is not Rails concern. asset-url helper is defined on sprockets so if we would implement this I think it is better to propose on sprockets repository.

Adrian Macneil

Thanks, I appreciate the constructive discussion. A rake task doesn't work for heroku, which is a large portion of deployments.

I'd really like to see either:

config.assets.nondigest = true

or

# this ties in nicely with other options such as config.assets.precompile
# and also means that people have to explicitly enable the feature on a per-file basis
config.assets.nondigest += %w(application.css logo.png)
Will Glynn

I agree with @adrianmacneil. I want this behavior for specific files. non-stupid-digest-assets implements this externally in 51 lines of Ruby.

Rafael Mendonça França

A rake task doesn't work for heroku, which is a large portion of deployments.

About this I call @schneems.

config.assets.nondigest += %w(application.css logo.png)

This is a good idea, I'd love to see a PR with it so we can discuss over the concrete code.

Ryan Angilly

@rafaelfranca for the config.assets.nondigest option, would it make sense for that option to also instruct Sprockets to not send the Cache-Control: public header on those files?

will-r

@rafaelfranca

asset-url(foo.jpg, caching: false)

I'm not sure about this, but this is not Rails concern. asset-url helper is defined on sprockets so if we would implement this I think it is better to propose on sprockets repository.

I was only suggesting that the whole 'cache problem' be made visible and therefore not your problem. Of course this would involve (small) changes both here and in sprockets, but it would remove any reason not to generate non-digest assets.

Richard Schneeman
Collaborator

I've been summoned!

I think instead of generating non-digest and digest files it would make more sense to have a middleware be able to understand that assets/foo.jpg means you want asset_path("foo.jpg"). This way your precompile is just as fast, your server is not bloated with 2x the number of assets and the behavior that is desired is preserved. The asset_path lookup shouldn't be significantly expensive as it's already done many times per each ERB page render. Another bennifit of this approach is that it is backwards compatible. We can use the middleware in 4.0+ and not have to upgrade all the way to 4.1 to get to it. I've suggested this path to a customer who spent days trying to modify their rake task via enhancethough i've not tried coding up this solution.

The cache issue in this case is very real, we probably should not set a far future expiration date.

While having to translate through a middleware and not telling the browser to cache assets would prove to be (ever so slightly) slower, I think in these cases speed is not as big of a concern as usability.

Rafael Mendonça França

@schneems this middleware is a good idea (and I think we are going to implement it in future) but it still doesn't fix some problems explained here. Some cases still require some assets to not having digests as the case where your application serves a shared asset to other applications and the email case.

Rafael Mendonça França

would it make sense for that option to also instruct Sprockets to not send the Cache-Control: public header on those files?

Assets are not always served by sprockets. Some are served by CDNs or Apache/Nginx proxies. So I think it is better to keep it simple and not add this cache control code now.

Ryan Angilly

@rafaelfranca Sorry if I'm being dense, but I'm not sure I follow you. Currently, sprockets always sends a public Cache-Control header (https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/server.rb#L198). I understand that CDNs or proxies will also serve assets, but I don't see how that factors in to discussing whether or not to turn off this header in Sprockets.

Adrien

@ryana , let's say you have nginx, in most scenarios to speed things up nginx directly serves assets to the client without touching a single line of ruby before that.

In this case, nginx chooses which cache headers to send, it does not have conscience of sprockets.

Rafael Mendonça França

When your application is using CDNs or proxies it will not reach sprockets. So fixing on sprockets will not help. I'm not sure how hekoru works though.

Will Glynn

Heroku recommends pointing CDNs to your app, e.g. Using Amazon CloudFront CDN. In this scenario, Cache-Control headers set by Sprockets would be honored, and it would be helpful if they were shorter than for fingerprinted assets.

Ryan Angilly

Yes I know how proxies work. I've used nginx and varnish and apache. I understand that there can be complex caching strategies implemented at layers above the Rack app. But my statement stands: I don't understand how this affects the discussion on how to customize the headers that Sprockets sends.

If someone is using a CDN or a proxy, it is that person's responsibility to make sure the correct caching strategy is in place. For everyone else, if we're going to tell sprockets to not generate digests for certain files, we need the ability to tell Sprockets "Hello Mr. Sprocket, this file over here might change without a change in filename, so please don't send a public Cache-Control header. xoxo"

Adrien

@ryana I get your point now, sorry.

Indeed this would be a good addition imo.

Richard Schneeman
Collaborator

Christ this thread is long. It’s going to get much longer.

Sprockets handles quite a few use cases, the hard part is each app will only use one out of many possibilities. You cannot just look at your use case without considering all the use cases. I’ve gone through the (entire) thread and i’m trying to condense all use cases. I’ve replied under why a middleware solution (as proposed earlier I see) could work.

This seems to be the sentiment on this thread

There hasn't been an explanation of why something so seemingly benign has been removed

I don’t think this feature was as benign as you might think. It can really trip people up when they’re setting a far future cache (as you should when serving assets). It may work for most use cases but when it blows up, it blows up in the worst way: silently due to improper cache invalidation.

Inline replies

middleware is an elegant patch but sadly no use if you're delivering the assets through a CDN.

@will-r i believe this is incorrect. A CDN would obey the cache-control rules here. If there are none the CDN will fetch a new version every time so your CDN still works, it just becomes less performant.

I'm not sure how heroku works though.

We run assets:precompile and then let the app serve assets config.serve_static_assets = true. The only downside here is that it’s slow to serve. If you use a CDN (which any production app should be doing) it suddenly becomes faster than even serving via NGINX. It takes minutes to set up a CDN, and it's practically free performance. It's 2014 there's no reason you should be running in production without a CDN.

Here’s the use-cases

Below them is how well a middleware solution would work.

  • Static 404 page referencing asset pipeline assets
    :heavy_check_mark:

  • Works with CDN
    :heavy_check_mark:

  • Reference a javascript file from a 3rd party app
    :heavy_check_mark:

  • jQuery libraries don’t know anything about the asset pipeline (changing url(..) to image-url("..”))
    :heavy_check_mark:

  • Doesn’t work with nginx as sprockets is turned off config.serve_static_assets = false

I think this is the wrong default setting. If NGINX sees the file in public and serves it then rails/sprockets will never see the request. If the file is not present i believe (will need to verify) that it will send the request to the application. Besides you should be using a CDN in front of NGINX even if you are using it to serve assets.

  • CDN performance problem: not using cache-control means CDNs and browsers don’t cache at all, meaning every asset request hits our servers every time.

This is a problem with middleware or any other solution. Even in Jeremy’s proposed symlinking solution you have to use a new version every time. That works for him, but won’t work for the case of having a 3rd party reference a javascript file. Here’s my proposal here we allow you to set a default cache-control for all middleware served assets (keep it low 10 minutes etc. by default is 0), Allow the middleware to take params ?cache-control=10000 which will dynamically set cache control. As most CDNs consider different query params a different cache object this will cause a new object lookup and the cache-control to be set to whatever you desire. Maybe this part is overkill or obviously a bad reason, but it is a place to start.

tl;dr

Symlinking or simply generating non-digest assets does not work (due to cache-invalidation) and it cannot be re-introduced. I think we can address all these use cases with a middleware option with some tweaking. If we choose not to fix this we should match production behavior to development to avoid #49 (comment) at the very least.

FWIW we had to add a section to Heroku documentation to address this expected behavior https://devcenter.heroku.com/articles/rails-4-asset-pipeline#only-generate-digest-assets as it was so unexpected for many

If i’ve left out a use case let me know.

Ryan Angilly

@schneems Much comment. Such A+. Would read again ;)

So as I understand it, your middleware solution would rewrite /assets/foo.jpg to asset_path('foo.jpg'). Am I also correct in assuming that when it had to do such a rewrite (and only when it had to do that rewrite) it would remove the Cache-Control header if one was sent up by a lower middleware layer (Sprockets), and ensure that an Etag was on the response?

The use case for that (which I actually just realized may not be in your response) is when you are Shopify and you want your users to include https://cdn.shopify.com/s/assets/external/app.js but app.js could change at any time.

Richard Schneeman
Collaborator

@ryana s/assets/external/app.js would need to be served without cache-control (set to 0) to make it update in realtime. If you're using Cloudfront it will respect cache-control so although the request goes through a CDN, the request immediately gets forwarded to your app server and it doesn't get cached. This is less than ideal (the CDN now adds latency), but perhaps setting to cache-control 60 may be close enough to real time for your application and although the cache will be reset 60 times a minute at least you get some benefit from the CDN.

So to clarify: by default we set cache-control to 0. This is the only way we can guarantee updated assets are served by CDN/browser/proxy/whatever. Allow the user to configure this with something like:

config.static_cache_control.non_digest = "public, max-age=60"

So by default we prefer usability and make performance configurable on a per-app basis by exposing a separate cache control setting.

Geoff Coffey
Richard Schneeman
Collaborator

Thanks for your input though this is a huge :bike: :house: we have to pick a default. No default will make everyone happy. The premise of this thread is that people are not happy that there was a feature regression without any warning. You are suggesting that we ignore that problem, prefer existing 4.x functionality and instead raise an error. A developer must now take action to have prior behavior which is no different from adding an extra gem which everyone here seems to agree is not a good thing.

Your issue is this: You have relied on assets failing in production to be a "feature" and my proposed change would take this feature away. We need a replacement way to make it obvious when you are doing the wrong thing(TM). A kneejerk workaround would be to remove the middleware http://guides.rubyonrails.org/rails_on_rack.html#highlighter_76637 now you're back at current functionality. Maybe a better solution would be to introduce a development dependency similar in nature to github.com/schneems/sprockets_better_errors that raises an error in development for performance tuning reasons.

At the end of the day we cannot have it "just work" which would make everyone on this thread happy, and have it "complain and blow up loudly when it's not performant". Active Record allows you to write really slow queries without complaint, yet if you are interested in tuning it there are a variety of tools and techniques available. Setting a config.static_cache_control.non_digest would actually make your non digest assets performant behind a CDN, so it's a pretty big leap of faith to assume using one SASS helper or another was incorrect (by default). I do believe this is an issue that should be addressed and and maybe even addressed in rails. I do not believe this is the place for forum to discuss this particular need at length. The core issue is "Inability to compile nondigest and digest assets breaks compatibility with bad gem" let's try to focus on that.

Keith Gaddis

@schneems I don't want to speak for anyone else, but for me the immediate issue is not a change in the defaults. Defaults change for good reasons, and I believe and agree that the defaults should serve the masses and what is believed to be "best practice" for the majority.

My issue (and I believe most will agree with me on this thread) is that not only were the defaults changed, but it was done so in a way in which it was impossible to change them back—so it wasn't just defaults, but capabilities themselves, were changed/removed. On a meta level, for a platform in use as widely as Rails, deprecating a feature like that is a policy mistake on the part of the maintainers and core team.

While I agree that the caching behavior for non-digested assets isn't desirable for most people, for some its essential, and most of us think of ourselves as grownups who are capable of making a tradeoff intelligently. I think everyone probably agrees that the development vs production thing is also a "bug". but most of all, what I've found frustrating following this thread was the vocal feedback on legitimate use-cases from plenty of developers, and the "too bad" attitude towards that point of view despite several people volunteering to submit PRs that would fix the problem in a non-obtrusive way.

To the maintainers:
I'd like to echo the sentiment that your work is appreciated. Seriously, thank you. When we've been banging our heads against a frustrating problem, its easy for consternation to take over my keyboard. But we all know (or should) that maintaining a high-profile project requires quite a bit of effort. That said, taking over a component of a high profile project like Rails may be a volunteer duty, but its a duty you volunteered for, and the community of users rightly expects a level of interaction that rises above "this isn't a problem for me, so I don't want to maintain that somewhat dusty corner of the library." Lastly, I appreciate the movement in the last couple of days to try to resolve this issue in a way that at least attempts to resolve the problems highlighted in the thread.

Adrian Macneil

I also want to add that I'm totally fine with the new default behavior. I'm more than happy to enable nondigest assets on a per-file basis, which hints to me that I'm doing the Wrong Thing, but still fixes the majority of use cases described above.

I think the middleware redirect above is smart. Although it won't fix the problem if people are using nginx to serve assets, it sounds like most people use a CDN directly in front of rails these days anyway. I also think removing caching headers for non digested files is sensible (the lack of cachability is part of the trade off).

Thanks again for all the work that has gone into this gem. It's really head and shoulders above anything else available out there.

zarqman

I've been bitten by the core issue here a few times: needing to reference consistently named .css and .js files from an external sources, such as email or 3rd party sites.

The middleware approach sounds like the best approach on the whole (thanks for proposing it @schneems). It addresses multiple core issues rather elegantly:

  • The redirect avoids having to keep a non-digested version of the file in sync, which has proven to be a problem at times.
  • It will work with nginx/apache (albeit with potentially reduced performance), as the typical configuration will pass-through the request and let the middleware handle the translation (probably assumes config.serve_static_assets = true). It may be possible to integrate with config.action_dispatch.x_sendfile_header to minimize the performance hit in some situations.
  • It goes a long way toward ensuring that assets still work when misconfigured, while also addressing the cache-control matter. The cache expiry issue very likely would benefit from middleware in certain deployment stacks, such as Heroku, even if another approach were to be pursued for the filenames. Might as well have it all in one place.
  • It's easily backported to/enabled on older versions of Rails.
  • It offers a way to assure that development and production behave the same way.

On this last point, middleware is not the only potential solution of course. Other work is happening in #84, #117, etc. This is encouraging and useful, as it would save countless hours on the part of not only developers, but everyone they ask for help. Since I'm going to assume the middleware will be able to be disabled (and might even default to that way), this other work is definitely not wasted.

As just hinted at, this new middleware doesn't have to be enabled by default. There is a precedent for enabling/disabling middleware based on a config setting (config.force_ssl as one example), so I wouldn't think it'd be too bothersome to do it here too.

All that said, I'm encouraging the following:

  1. Create the middleware, hopefully as a default part of the Rails stack somewhere. It's a viable solution that addresses a couple real, in-the-wild problems.

  2. Continue the discussion on whether the best default behavior for Rails assets is to just-work or to strongly-encourage-good-behavior.

If the consensus is to just work, then enable the middleware by default. This should also implicitly solve the development/production behavioral divergence issue.

On the other hand, if the consensus is to encourage the right thing, then disable the middleware by default. The middleware will still exist for those that have more diverse needs or other personal reasons for wanting that behavior.

zarqman

For those interested, I've taken a stab at this middleware: https://github.com/zarqman/smart_assets

Paul Wittmann

+1 for optional asset paths without a digest.

David Rojas Camaggi

Another option is to create soft link from the latest assets

namespace :assets do

  desc "Create soft links as non digested assets"
  task soft_links: :environment do
    Rake::Task['assets:precompile'].invoke
    assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
    manifest_path = assets.find { |f| f =~ /(manifest)(-{1}[a-z0-9]{32}\.{1}){1}/ }
    manifest_data = JSON.load(File.new(manifest_path))
    assets_data = manifest_data["assets"].each do |asset_name, file_name|
      file_path = File.join(Rails.root, 'public/assets', file_name)
      asset_path = File.join(Rails.root, 'public/assets', asset_name)
      FileUtils.ln_s(file_path, asset_path, :force => true)
    end
  end

end
Jon Wu

I'm running into this now as I'm upgrading to Rails 4. I'm looking for non-digested assets for the reasons listed here, but another reason I need them is as a fallback for older assets.

I have pages and paths of digested assets cached in other non-Rails parts of my application. These pages may be cached by a reverse proxy and could thus serve up digests that no longer exist.

I used to solve this by catching a 404 for a stale asset and redirecting to the non-digested asset with a short cache-control header. Before I did this, I found that sending out a bunch of deploys during the middle of the day would lead to missing assets and a broken experience for many users.

I'm sure this scenario isn't common as I'm parsing the manifest and using it in my Java app, but I wanted to share this use case. For now, I'll be trying some of the workarounds listed here.

Brad Werth

+1 for optional asset paths without a digest.

Joe Van Dyk

I don't really understand why the rake task that generates assets can't also make a copy of the file to a non-digested filename.

namespace :assets do
  task :precompile do
    assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
    manifest_path = assets.find { |f| f =~ /(manifest)(-{1}[a-z0-9]{32}\.{1}){1}/ }
    manifest_data = JSON.load(File.new(manifest_path))
    manifest_data["assets"].each do |asset_name, file_name|
      file_path  = File.join(Rails.root, 'public/assets', file_name)
      asset_path = File.join(Rails.root, 'public/assets', asset_name)
      FileUtils.cp(file_path, asset_path)
    end
  end
end

Adding that to my Rakefile solved the issue.

BrandonMathis

I was able to sidestep this issue by just copying minifyed js that I didn't want digested into a public/javascripts folder.

Michael Darmousseh

I haven't chimed in in a while, but I want to definitely +1 the Rack Middleware solution.

If we can add the must-revalidate tag and the last-modified header. Ideally, each file should have an associated last-modified date that gets updated when the file gets updated. This would make http caching very valuable while still solving the issue for a lot. Of course this solution means that an app is likely to receive a lot more request than if we can use modified-dates in the file name, but this is probably the next best solution.

Alex Coles myabc referenced this issue in opf/openproject
Merged

Precompile some assets without a digest #1379

Saurabh Nanda

Where can one read the rationale for why the default behaviour was changed? We lived with the previous behaviour for so many years, what exactly was the problem/bug/security-issue this change fixed?

Andrew Kaspick

I'm not sure of the actual reason, but I do know that before it used to take a LONG time to compile assets on a deploy because it would look through basically everything in an app and gems and compile it. Now it's quick and speedy only compiling the desired assets. A deploy for one of my apps went from over 5 minutes to roughly 30 seconds.

Ryan Angilly

@saurabhnanda I believe the rationale was that the previous behavior, despite being around for a while, was decided to be a poor pattern since it encouraged instances of stale assets being cached out on edge locations (ie. the new application.js doesn't get picked up when it changes). The new changes make it impossible for an asset to be stale (since the name changes), while still letting Rails safely use use cache headers that maximize end-user performance.

One of the discussions going on in this thread -- and IMO, the most important one ;) -- center around the fact that in this new world it's not possible out of the box to use the asset pipeline to generate an asset (ie. my-widget.js) that can be referenced by a 3rd party (ie. If you have a JS tag generated by the asset pipeline, then your customer cannot install that JS tag on their site because the name of the generated file keeps changing).

@akaspick I believe the decreases in compile time had little to no impact on why this change was made. Furthermore, Rails4 brought in some optimizations from turbo-sprockets et al that only compile assets when they need to be changed. That was a big performance boost.

Matthijs Langenberg

Is it really that difficult to only set far future expire headers for filenames containing a fingerprint?

location ~ "^/assets/.*-[0-9a-f]{32}.*" {
  gzip_static on;
  expires max;
  add_header Cache-Control public;
  break;
}

Add this to your Nginx configuration and you can safely use cache headers to maximize end-user performance without risking application.js getting stale.

You would refer to digest-filenames from your Rails app, while 3rd party can still reference my-widget.js.

Jon Wu

@mlangenberg, this won't work in situations where an asset isn't consistently available.
There are 2 scenarios for this in a scaled environment:

  1. The asset doesn't exist yet because it's too new. This can happen during a rolling deployment. Maybe you get HTML from one server that has just restarted and has the newest version of the page with fingerprints for the latest asset. However, their browser then makes another request which is load balanced to a server which hasn't restarted yet. In a dumb horizontal architecture without any kind of stickyness, you'd get a 404 for the asset. As I mentioned above, my solution for this was to write a rule to catch the 404, then proxy the non-digested version with short cache-control headers (at the old URL to avoid an extra round trip).
  2. The asset is too old and has been cleaned up after multiple quick deployments. If Sprokets only keeps a few versions of each asset, what if you deploy 4 times in a row very quickly? What if your entire site is cached by a CDN and it's is still serving slightly stale versions of the page while the cache is invalidated - even if only for 15-30 seconds? The HTML will then again refer to assets which potentially don't exist.

In either case, non-digested assets alone don't fix the issue, but they make serving the correct / most recent version of file much more feasible. I've solved this with another gem for now but hopefully this use case makes sense. I also agree with difficulties serving static assets for JS libraries too, but that hasn't been as big of an issue for me personally. I can just put the files outside of Rails.

Denis

This is so wrong... Anybody who believes this issue should remain closed, must rethink. The single most powerful source of pain for thousands of Rails developers, because of somebody's personal subjective judgement of what is a bad pattern and what isn't.

Rafael Mendonça França rafaelfranca locked and limited conversation to collaborators
Rafael Mendonça França

Thank you. I locked this conversation. We already have enough information to think about this issue and in fact we are going to handle it in some way (we already did some improvements on master branch to alleviate the pain). If we think we need more feedback from the community I'll reopen the thread.

Marcel Sackermann m0gg referenced this issue from a commit in m0gg/dart-rails
Marcel Sackermann m0gg Bump Version, update README
  * due to sprockets digest method, we are forced to use a workaround to allow
  "precompilation" of .dart files, see [non-stupid-digest-assets](https://github.com/alexspeller/non-stupid-digest-assets)
  and [Inability to compile nondigest and digest assets breaks compatibility with bad gems #49](rails/sprockets-rails#49)
  it is optionally (and automatically) available by adding `gem 'non-stupid-digest-assets', '>= 1.1', github: 'm0gg/non-stupid-digest-assets'
` to your Gemfile
  * added dart_app.js to precompile list
  * faced an issue with UglifyJs stackoverflowing with too large dart2js files
08184e8
Vincent Untz vuntz referenced this issue from a commit in vuntz/barclamp-crowbar
Vincent Untz vuntz Add rake task to create non-digest assets symlinks
Based on
rails/sprockets-rails#49 (comment)

Without this, a lot of things just don't work (including static pages).
e4cfc2d
Thomas Boerger tboerger referenced this issue from a commit in tboerger/barclamp-crowbar
Vincent Untz vuntz Add rake task to create non-digest assets symlinks
Based on
rails/sprockets-rails#49 (comment)

Without this, a lot of things just don't work (including static pages).
f015c17
Thomas Boerger tboerger referenced this issue from a commit in tboerger/barclamp-crowbar
Vincent Untz vuntz Add rake task to create non-digest assets symlinks
Based on
rails/sprockets-rails#49 (comment)

Without this, a lot of things just don't work (including static pages).
6d283f6
Thomas Boerger tboerger referenced this issue from a commit in tboerger/barclamp-crowbar
Vincent Untz vuntz Add rake task to create non-digest assets symlinks
Based on
rails/sprockets-rails#49 (comment)

Without this, a lot of things just don't work (including static pages).
8445854
Thomas Boerger tboerger referenced this issue from a commit in tboerger/barclamp-crowbar
Vincent Untz vuntz Add rake task to create non-digest assets symlinks
Based on
rails/sprockets-rails#49 (comment)

Without this, a lot of things just don't work (including static pages).
803379c
Thomas Boerger tboerger referenced this issue from a commit in tboerger/barclamp-crowbar
Vincent Untz vuntz Add rake task to create non-digest assets symlinks
Based on
rails/sprockets-rails#49 (comment)

Without this, a lot of things just don't work (including static pages).
dea4ad8
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Something went wrong with that request. Please try again.