Question

In sprockets how do I detect if an asset is stale?

I've tried the following and my results were unexpected:

e = Rails.application.assets # sprockets env
x = Rails.application.assets.index

e['path/to/my/asset'].body
#=> prints asset

e['path/to/my/asset'].fresh?(x)
#=> true


# modify the asset file (to change mtime and digest)


e['path/to/my/asset'].fresh?(x)
#=> true

#!? Why wasn't that false?

The caching mechanism confuses me. Further, when inspecting the asset it tells me that the mtime is the original value, not time I modified the file above. Can someone explain what's going on here and how I can detect a stale asset? My hope is to leverage the sprockets dependency/caching system in my gem.

My Goal:

I'm creating a gem that finds assets in the pipeline and generates some content from them. This gem integrates with ActionView which complicates things by doing its own caching. I need some way to bust ActionView's cache if the asset in sprockets is stale and will be reloaded on next fetch. Rather than mirror sprocket's caching system in my gem, I was hoping to just ask sprockets about the state of its assets - which seems totally possible, if only I could figure out what was going on.

Was it helpful?

Solution

I can't answer how to get around this, but I can (with some confidence) tell you why its behaving as it is. Sprockets doesn't only mtime to determine staleness, it uses a digest of the file itself. It will return the asset as fresh first if the mtime hasn't been recently updated, and secondly if the hash digest is unchanged (for the relevant method, look here for dependency_fresh?). Since a touch won't change the hash of a file, Sprockets will consider it fresh.

I don't know quite what you're goal is here, so I can't give much advice here. The dependency tracking that is used is mostly private, but it would be possible to hack around this to force a reset. If what you're looking for is a quick way to force an asset to be stale for the sake of local testing while developing a gem, you may consider creating a monkey patch for Asset or ProcessedAsset that can flush the old mtime and digest values.


EDIT - I've done a bit more digging, and I think I found some useful things. The index method on assets creates a new object on each call, and is in effect a snapshot of the assets at the time, while the environment will constantly refresh when you ask it for an asset - looking up an asset causes it to automatically refresh that asset if it is stale.

In theory, this should have a surprisingly easy solution - just invert your fresh calls to x['path/to/asset'].fresh?(e).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top