The scenario is a normal model that contains a paperclip attachment along with some other columns that have various validations. When a form to to create an object cannot be saved due to a validation error unrelated to the attachment, columns like strings are preserved and remain prefilled for the user, but a file selected for uploading is completely lost and must be reselected by the user.
Is there a standard approach to preserving the attachment in the case of a model validation error? This seems like a very common use case.
It seems inelegant to hack up a solution where the file is saved without an owner and then reconnected to the object after it's successfully saved so I'm hoping to avoid this.
Switch to using CarrierWave. I know this was in a comment, but I just spent all day making the transition so my answer may be helpful still.
First you can follow a great railscast about setting up carrier wave: http://railscasts.com/episodes/253-carrierwave-file-uploads
To get it to preserve the image between posts, you need to add a hidden field with the suffix 'cache':
<%= form_for @user, :html => {:multipart => true} do |f| %>
<p>
<label>My Avatar</label>
<%= f.file_field :avatar %>
<%= f.hidden_field :avatar_cache %>
</p>
<% end %>
And if you're deploying to Heroku like I am, you need to make some changes to get it to work, since the caching works by temporarily saving uploads in a directory called public/uploads. Since the filesystem is readonly in Heroku, you need to have it use the tmp folder instead, and have rack serve static files from there.
In your config/initializers/carrierwave.rb (feel free to create if not there), add:
CarrierWave.configure do |config|
config.root = Rails.root.join('tmp')
config.cache_dir = 'carrierwave'
end
In your config.ru file, add:
use Rack::Static, :urls => ['/carrierwave'], :root => 'tmp'
For an example of a fully functional barebones rails/carrierwave/s3/heroku app, check out:
https://github.com/trevorturk/carrierwave-heroku (no affiliation, just was useful).
Hope this helps!