This project is archived and is in readonly mode.
Rails 3.0.0-pre - stylesheet_link_tag, javascript_include_tag cache fails when using File.atomic_write: Invalid cross-device link
Reported by tadman | February 11th, 2010 @ 05:37 AM | in 3.0.6
In Rails 3.0.0-pre, when caching JavaScript and CSS assets, a mysterious error is generated on systems with a separate partition for temporary files.
ActionView::Helpers.write_asset_file_contents makes use of File.atomic_write with no tmp_dir parameter specified. This defaults to Dir.tmpdir accordingly, however, it appears that if this directory is on a different volume than the Rails application then an error will result when apparently trying to create a hard-link to move the cached asset file:
ActionView::Template::Error (Invalid cross-device link - /tmp//_main.css20100210-24481-ilznwv-0 or public/stylesheets/_main.css)
This was generated from a simple asset-caching request:
stylesheet_link_tag('reset', 'master', 'forms', :cache => '_main')
This would only seem to be an issue on systems where Dir.tmpname returns a path on a different volume than where Rails.root is situated. On some Linux installations /tmp is given its own partition.
A simple patch is to use the default Rails tmp/ directory by modifying the call in write_asset_file_contents to be:
module ActionView
module Helpers
def write_asset_file_contents(joined_asset_path, asset_paths)
FileUtils.mkdir_p(File.dirname(joined_asset_path))
File.atomic_write(joined_asset_path, File.join(Rails.root, 'tmp')) { |cache| cache.write(join_asset_file_contents(asset_paths)) }
# Set mtime to the latest of the combined files to allow for
# consistent ETag without a shared filesystem.
mt = asset_paths.map { |p| File.mtime(asset_file_path(p)) }.max
File.utime(mt, mt, joined_asset_path)
end
end
end
It stands to reason that the environment could be tweaked so that TMPDIR is assigned accordingly somewhere during the initialization, but that may alter behavior on a much larger scale.
The previous implementation in Rails 2.3.5 does not use atomic_write and does not suffer from this problem:
File.open(joined_asset_path, "w+") { |cache| cache.write(join_asset_file_contents(asset_paths)) }
This has the unfortunate effect of presumably failing if the Rails application does not have its own tmp/ directory.
Comments and changes to this ticket
-
renchap March 8th, 2010 @ 01:03 PM
Same problem here, /tmp is on a different partition and I get the error.
-
Scott Marshall March 22nd, 2010 @ 06:26 PM
I can confirm that atomic_write is indeed the culprit.
write_asset_file_contents calls it without a tmp path argument so it defaults to the system tmp dir which normally is /tmp.
Being able to configure an alternate tmp dir for atomic writes would solve the problem.
-
Yehuda Katz (wycats) March 27th, 2010 @ 07:54 AM
- State changed from new to open
- Tag changed from actionview to actionview, rails3
- Assigned user set to Yehuda Katz (wycats)
- Milestone cleared.
-
Jeremy Kemper August 30th, 2010 @ 04:10 AM
- Milestone cleared.
- Importance changed from to High
-
uggleader November 8th, 2010 @ 09:54 AM
- no changes were found...
-
Santiago Pastorino February 27th, 2011 @ 03:15 AM
- Milestone changed from 3.0.5 to 3.0.6
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>