Module: EchoUploads::TmpFileWriting
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/echo_uploads/tmp_file_writing.rb
Overview
This comment is current as of Rails 4.2.5.
This module writes temporary EchoUploads::Files on failed attempts to save the main ActiveRecord model. Because ActiveRecord wraps save attempts in transactions, we can’t use after_save callbacks. If we tried, the EchoUploads::Files would be lost upon rollback. Instead, we have to wrap the #save, #create, and #update methods so that the EchoUploads::Files are saved outside the transactions.
Here is the ancestor chain for ActiveRecord::Base, including this module, highest-priority first:
EchoUploads::TmpFileWriting -> ActiveRecord::Transactions -> ActiveRecord::Persistence
Here is the control flow for each of the main persistence methods. (T) denotes that the method wraps all subsequent calls in a transaction.
#save
EchoUploads::TmpFileWriting#save -> ActiveRecord::Transactions#save (T) ->
ActiveRecord::Persistence#save
#create
ActiveRecord::Persistence#create -> EchoUploads::TmpFileWriting#save ->
ActiveRecord::Transactions#save (T) -> ActiveRecord::Persistence#save
#update
EchoUploads::TmpFileWriting#update -> ActiveRecord::Persistence#update (T) ->
EchoUploads::TmpFileWriting#save -> ActiveRecord::Transactions#save (T) ->
ActiveRecord::Persistence#save
Per the above, #save and #create are easy enough: We just wrap #save. But #update is problematic because it starts its own transaction and then delegates to #save. Because of that outer transaction, we can’t rely on the #save wrapper. Instead, we have to wrap #update. To prevent writing the temp file twice (once in #update and again in #save), #update sets @echo_uploads_persistence_wrapped. This tells the #save wrapper not to write the temp file.
Defined Under Namespace
Modules: ClassMethods
Instance Method Summary collapse
-
#echo_uploads_maybe_write_tmp_file(attr, options) ⇒ Object
On a failed attempt to save (typically due to validation errors), save the file and metadata.
- #echo_uploads_persistence_wrapper ⇒ Object
- #save ⇒ Object
- #update ⇒ Object (also: #update_attributes)
Instance Method Details
#echo_uploads_maybe_write_tmp_file(attr, options) ⇒ Object
On a failed attempt to save (typically due to validation errors), save the file and metadata. Metadata record will be given the temporary flag.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/echo_uploads/tmp_file_writing.rb', line 49 def echo_uploads_maybe_write_tmp_file(attr, ) if (file = send(attr)).present? and errors[attr].empty? # A file has been uploaded. Validation failed, but the file itself was valid. # Thus, we must persist a temporary file. # # It's possible at this point that the record already has a permanent file. # That's fine. We'll now have a permanent and a temporary one. The temporary # one will replace the permanent one if and when the user resubmits with # valid data. # Construct an array of EchoUploads::File instances. The array might have only # one element. if [:multiple] mapped_files = send("mapped_#{attr}") || raise('echo_uploads called with :multiple, but :map option was missing') = mapped_files.map do |mapped_file| ::EchoUploads::File.new( owner: nil, temporary: true, expires_at: [:expires].from_now, file: mapped_file ) end else = [::EchoUploads::File.new( owner: nil, temporary: true, expires_at: [:expires].from_now, file: send(attr) )] end # Persist each file. (There might only be one, though.) .each do || .persist! attr, end # Set the attr_tmp_metadata attribute so the form can remember our records. send("#{attr}_tmp_metadata=", ) end end |
#echo_uploads_persistence_wrapper ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/echo_uploads/tmp_file_writing.rb', line 87 def echo_uploads_persistence_wrapper success = yield unless success self.class.echo_uploads_save_wrapper.each do |attr, | echo_uploads_maybe_write_tmp_file(attr, ) end if self.class.included_modules.include? ::EchoUploads::Callbacks run_callbacks :failed_save end end success end |
#save ⇒ Object
101 102 103 104 105 106 107 |
# File 'lib/echo_uploads/tmp_file_writing.rb', line 101 def save(*) if @echo_uploads_persistence_wrapped super else echo_uploads_persistence_wrapper { super } end end |
#update ⇒ Object Also known as: update_attributes
110 111 112 113 114 115 116 117 118 119 |
# File 'lib/echo_uploads/tmp_file_writing.rb', line 110 def update(*) echo_uploads_persistence_wrapper do begin @echo_uploads_persistence_wrapped = true super ensure @echo_uploads_persistence_wrapped = nil end end end |