I set up a story
model with an image
attachment handled by Paperclip, that looks like:
class Story < ActiveRecord::Base
has_attached_file :image # [...]
attr_accessible :user_id, :title, :image, :image_file_name
belongs_to: user
validates_presence_of :user_id
validates :title, :length => { :maximum => 50 }
validates_attachment_size :image, :less_than => 2.megabytes, :unless => Proc.new { |story| story[:image].nil? }
# [...]
end
When I fill my story form, that looks like:
<%= form_for @story, html: { multipart: true } do |f| %>
<% if @story.errors.any? %>
<div id="error-explanation">
<ul>
<% @story.errors.full_messages.each do |msg| %>
<li class="error-mess">Error: <%= msg.downcase %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field :title %></td>
<%= f.file_field :image %>
<%= f.submit t('.send') %>
<% end %>
If validation fails for a story.title too long the form is redisplayed correctly along with the proper error message and the invalid title already filled in, but the file_field
is now blank and I have to click again on it in order to re-select the file I want to upload.
And here is how my stories_controller.rb looks like:
def create
@story = @current_user.stories.new(params[:story])
if @story.save
redirect_to thanks_path
else
# [email protected] so I render action 'new' again just to
# bang my head against this 'anomaly'
render action: "new"
end
end
How can I avoid users having to re-select the file to upload after a validation error?
The way HTTP file uploads work in browsers, the file has been uploaded to your app already on first submit – so you should store it somewhere, so that you still have access to it later on a second form submit. (At least in PHP an uploaded file get’s deleted after the script has run, if it’s not explicitly been moved somewhere else – I don’t know if that applies for RoR as well.)
You can’t pre-fill an input type=file field in HTML – for security reasons. And even if the user picks the file again, they would have to send it a second time – waste of user’s and your bandwidth.
So either store it somewhere on first submit, or try to do your validations on the client-side too with JavaScript before allowing submit (as far as possible), so that you minimize the form submits that actually fail validation on the server side.
CBroe is right, the best solution is to store the file temporarily. What I would do to do this is: - Move the file to a temp directory, and name it with the id of the user that was trying to upload it. - When the form is posted and there is no file uploaded, try to use the temp file for that user (if it exists). - If the Story is succesfully saved, delete any temp files for that user.
I think that should do the trick.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With