Module: EchoUploads::TempFileSaving

Defined in:
lib/echo_uploads/temp_file_saving.rb

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



3
4
5
# File 'lib/echo_uploads/temp_file_saving.rb', line 3

def self.included(base)
  base.class_eval { extend ClassMethods }
end

Instance Method Details

#maybe_save_temp_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.

To deal with the various persistence methods (#save, #create, #update_attributes), and the fact that ActiveRecord rolls back the transaction on validation failure, we can’t just use a convenient after_validation callback. Instead, we have to do some trickery with .alias_method_chain.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/echo_uploads/temp_file_saving.rb', line 14

def maybe_save_temp_file(attr, options)
  success = yield
  
  # Because of the tangled way ActiveRecord's persistence methods delegate to each
  # other, maybe_save_temp_file sometimes gets called twice. That's unavoidable. To
  # workaround that issue, we check whether we're calling #save from within #update.
  @echo_uploads_saving ||= {}
  @echo_uploads_updating ||= {}
  unless @echo_uploads_saving[attr] and @echo_uploads_updating[attr]
    if (file = send(attr)).present? and !success 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 options[:multiple]
        mapped_files = send("mapped_#{attr}") ||
          raise('echo_uploads called with :multiple, but :map option was missing')
        metas = mapped_files.map do |mapped_file|
          ::EchoUploads::File.new(
            owner: nil, temporary: true, expires_at: options[:expires].from_now,
            file: mapped_file
          )
        end
      else
        metas = [::EchoUploads::File.new(
          owner: nil, temporary: true, expires_at: options[:expires].from_now,
          file: send(attr)
        )]
      end
      
      # Persist each file. (There might only be one, though.)
      metas.each do |meta|
        meta.persist! attr, options
      end
      
      # Set the attr_tmp_metadata attribute so the form can remember our records.
      send("#{attr}_tmp_metadata=", metas)
    end
  end
  
  success
end