Module: Dscf::Core::FileUploadable
- Extended by:
- ActiveSupport::Concern
- Included in:
- FilesController
- Defined in:
- app/controllers/concerns/dscf/core/file_uploadable.rb
Overview
Include this concern in controllers that need to handle file uploads Works seamlessly with Dscf::Core::Common for automatic file handling in CRUD operations
File validation happens BEFORE save, and if it fails, the entire operation is rolled back. This ensures atomic behavior - either everything succeeds or nothing is saved.
Instance Method Summary collapse
-
#after_save_hook(record) ⇒ Object
Hook called by Common module after create/update Automatically attaches files from params with strict validation.
-
#attach_files(record, attachment_name, files, **options) ⇒ Boolean
Attach files to a model’s attachment field.
-
#auto_attach_files(record, namespace: nil) ⇒ Boolean
Automatically attach file uploads from params to a record Detects file params and attaches them to matching model attachments.
-
#file_upload_strict_mode? ⇒ Boolean
Whether to fail the entire operation if file upload fails Override in controller to change behavior.
-
#process_base64_file(base64_data, filename:, content_type:) ⇒ Hash
Process base64 encoded file.
-
#send_attachment(attachment, **options) ⇒ Object
Download a file from an attachment.
-
#send_stored_file(file_key, **options) ⇒ Object
Download a file and send it as response.
-
#upload_base64_file(base64_data, filename:, content_type:, **options) ⇒ Hash?
Upload a base64 encoded file.
-
#upload_file(file, **options) ⇒ Dscf::Core::FileStorage::Attachment?
Upload a file directly (without attaching to a model) Useful for standalone upload endpoints.
-
#upload_files(files, **options) ⇒ Array<Hash>
Upload multiple files directly.
Instance Method Details
#after_save_hook(record) ⇒ Object
Hook called by Common module after create/update Automatically attaches files from params with strict validation
50 51 52 53 54 55 56 57 58 59 60 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 50 def after_save_hook(record) super if defined?(super) success = auto_attach_files(record) # In strict mode, raise error to trigger rollback if upload failed return unless !success && file_upload_strict_mode? = @file_upload_errors&.first || "File upload failed" raise FileUploadError, end |
#attach_files(record, attachment_name, files, **options) ⇒ Boolean
Attach files to a model’s attachment field
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 75 def attach_files(record, , files, **) return true if files.blank? return true unless record.respond_to?() = record.send() return true unless .respond_to?(:attach) # Auto-set uploaded_by if available = .uploaded_by(current_user) if respond_to?(:current_user) && current_user result = .attach(files, **) unless result @file_upload_errors ||= [] @file_upload_errors.concat(Array(.errors)) end result end |
#auto_attach_files(record, namespace: nil) ⇒ Boolean
Automatically attach file uploads from params to a record Detects file params and attaches them to matching model attachments
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 100 def auto_attach_files(record, namespace: nil) @file_upload_errors = [] # Use custom file params if defined files_to_attach = if respond_to?(:file_upload_params, true) file_upload_params else extract_file_params(record, namespace) end all_success = true files_to_attach.each do |, file_value| success = attach_files(record, .to_sym, file_value) all_success = false unless success end all_success end |
#file_upload_strict_mode? ⇒ Boolean
Whether to fail the entire operation if file upload fails Override in controller to change behavior
65 66 67 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 65 def file_upload_strict_mode? true end |
#process_base64_file(base64_data, filename:, content_type:) ⇒ Hash
Process base64 encoded file
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 202 def process_base64_file(base64_data, filename:, content_type:) return nil if base64_data.blank? # Handle data URL format: "data:image/png;base64,..." if base64_data.include?(",") content_type_match = base64_data.match(/data:([^;]+);base64/) content_type = content_type_match[1] if content_type_match base64_data = base64_data.split(",").last end decoded = Base64.decode64(base64_data) io = StringIO.new(decoded) { io: io, filename: filename, content_type: content_type } end |
#send_attachment(attachment, **options) ⇒ Object
Download a file from an attachment
183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 183 def (, **) unless &.attached? render json: {error: "File not found"}, status: :not_found return end send_stored_file( .file_key, filename: [:filename] || .filename, content_type: [:content_type] || .content_type, disposition: [:disposition] || "inline" ) end |
#send_stored_file(file_key, **options) ⇒ Object
Download a file and send it as response
166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 166 def send_stored_file(file_key, **) client = FileStorage::Client.new result = client.download(file_key) send_data( result[:data], filename: [:filename] || result[:filename], type: [:content_type] || result[:content_type], disposition: [:disposition] || "inline" ) rescue FileStorage::Client::DownloadError => e render json: {error: e.}, status: :not_found end |
#upload_base64_file(base64_data, filename:, content_type:, **options) ⇒ Hash?
Upload a base64 encoded file
228 229 230 231 232 233 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 228 def upload_base64_file(base64_data, filename:, content_type:, **) file_hash = process_base64_file(base64_data, filename: filename, content_type: content_type) return nil unless file_hash upload_file(file_hash, **) end |
#upload_file(file, **options) ⇒ Dscf::Core::FileStorage::Attachment?
Upload a file directly (without attaching to a model) Useful for standalone upload endpoints
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 124 def upload_file(file, **) @file_upload_errors = [] if file.blank? @file_upload_errors << "No file provided" return nil end uploader = FileStorage::Uploader.new() result = uploader.upload(file) unless result @file_upload_errors = uploader.errors return nil end result end |
#upload_files(files, **options) ⇒ Array<Hash>
Upload multiple files directly
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'app/controllers/concerns/dscf/core/file_uploadable.rb', line 147 def upload_files(files, **) @file_upload_errors = [] if files.blank? @file_upload_errors << "No files provided" return [] end uploader = FileStorage::Uploader.new() results = uploader.upload_many(files) @file_upload_errors = uploader.errors unless uploader.success? results end |