Improve file upload UX with validation and uploaded files display

Enhanced the benefit forms file upload functionality to provide better
user feedback and visibility of uploaded files.

Changes:
1. Added file type validation in controller:
   - Only accepts PDF, DOC, DOCX, JPG, PNG formats
   - Shows clear error message with the rejected file extension

2. Added file size validation:
   - Maximum 10MB file size limit
   - Shows file size in error message if exceeded

3. Improved success/error messages:
   - Shows specific filename on successful upload
   - Shows detailed error messages for validation failures

4. Added uploaded files display section:
   - Lists all uploaded files with icons based on file type
   - Shows file size and upload timestamp
   - Provides download button for each file
   - Only displays when files exist

Before: Users received generic "Something went wrong" message with no
indication of why uploads failed. No way to see uploaded files.

After: Clear validation feedback tells users exactly what went wrong
(wrong format, too large, etc.) and uploaded files are visible with
download links.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ken Johnson
2025-12-11 12:24:52 +00:00
parent c7c9619a36
commit f21da3f075
2 changed files with 92 additions and 5 deletions
+40 -5
View File
@@ -3,6 +3,15 @@ class BenefitFormsController < ApplicationController
def index
@benefits = Benefits.new
# List uploaded files
data_path = Rails.root.join("public", "data")
@uploaded_files = Dir.glob("#{data_path}/*").reject { |f| File.directory?(f) || File.basename(f) == '.gitkeep' }.map do |file|
{
name: File.basename(file),
size: File.size(file),
modified: File.mtime(file)
}
end.sort_by { |f| f[:modified] }.reverse
end
def download
@@ -17,12 +26,38 @@ class BenefitFormsController < ApplicationController
def upload
file = params[:benefits][:upload]
if file
flash[:success] = "File Successfully Uploaded!"
Benefits.save(file, params[:benefits][:backup])
else
flash[:error] = "Something went wrong"
if file.nil?
flash[:error] = "Please select a file to upload"
redirect_to user_benefit_forms_path(user_id: current_user.id)
return
end
# Validate file type
allowed_extensions = %w[.pdf .doc .docx .jpg .jpeg .png]
file_extension = File.extname(file.original_filename).downcase
unless allowed_extensions.include?(file_extension)
flash[:error] = "Invalid file type. Accepted formats: PDF, DOC, DOCX, JPG, PNG. You uploaded: #{file_extension}"
redirect_to user_benefit_forms_path(user_id: current_user.id)
return
end
# Validate file size (10MB max)
max_size = 10.megabytes
if file.size > max_size
flash[:error] = "File too large. Maximum size: 10MB. Your file: #{(file.size / 1.megabyte.to_f).round(2)}MB"
redirect_to user_benefit_forms_path(user_id: current_user.id)
return
end
begin
Benefits.save(file, params[:benefits][:backup])
flash[:success] = "File '#{file.original_filename}' uploaded successfully!"
rescue => e
flash[:error] = "Failed to upload file: #{e.message}"
end
redirect_to user_benefit_forms_path(user_id: current_user.id)
end
+52
View File
@@ -118,6 +118,58 @@
</div>
</div>
<!-- Uploaded Files Section -->
<% if @uploaded_files.any? %>
<div class="row mt-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-white py-3">
<h4 class="mb-0">
<i class="bi bi-folder2-open text-success"></i> Uploaded Files
</h4>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th><i class="bi bi-file-earmark"></i> File Name</th>
<th><i class="bi bi-hdd"></i> Size</th>
<th><i class="bi bi-clock"></i> Uploaded</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% @uploaded_files.each do |file| %>
<tr>
<td>
<% icon_class = case File.extname(file[:name]).downcase
when '.pdf' then 'bi-file-earmark-pdf text-danger'
when '.doc', '.docx' then 'bi-file-earmark-word text-primary'
when '.jpg', '.jpeg', '.png' then 'bi-file-earmark-image text-success'
else 'bi-file-earmark'
end %>
<i class="bi <%= icon_class %> me-2"></i>
<strong><%= file[:name] %></strong>
</td>
<td><%= number_to_human_size(file[:size]) %></td>
<td><%= file[:modified].strftime("%b %d, %Y at %I:%M %p") %></td>
<td>
<%= link_to download_path(type: "File", name: "public/data/#{file[:name]}"), class: "btn btn-sm btn-outline-primary" do %>
<i class="bi bi-download"></i> Download
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<% end %>
<!-- Info Box -->
<div class="row mt-4">
<div class="col-12">