Class: DataShift::Paperclip::AttachmentLoader

Inherits:
LoaderBase
  • Object
show all
Includes:
DataShift::Paperclip
Defined in:
lib/datashift/loaders/paperclip/attachment_loader.rb

Instance Attribute Summary collapse

Attributes included from DataShift::Paperclip

#attachment

Attributes inherited from LoaderBase

#binder, #doc_context, #file_name

Attributes included from Delimiters

#attribute_list_end, #attribute_list_start, #csv_delimiter, #key_value_sep, #text_delim

Instance Method Summary collapse

Methods included from DataShift::Paperclip

#create_paperclip_attachment, #get_file, get_files, #process_missing_records

Methods included from Logging

#logdir, #logdir=, #logger, #verbose

Methods inherited from LoaderBase

#abort_on_failure?, #bind_headers, #configure_from, #load_object_class, #report, #reset, #run, #set_headers, #setup_load_class

Methods included from Querying

#find_or_new, #get_record_by, #get_record_by!, #search_for_record, where_field_and_values

Methods included from Delimiters

#column_delim, #column_delim=, #eol, #multi_assoc_delim, #multi_assoc_delim=, #multi_facet_delim, #multi_value_delim, #multi_value_delim=, #name_value_delim, #name_value_delim=, #setmulti_facet_delim

Constructor Details

#initializeAttachmentLoader

Returns a new instance of AttachmentLoader.



26
27
28
29
30
31
32
33
34
35
36
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 26

def initialize
  super

  @attach_to_klass = nil
  @attach_to_find_by_field = nil
  @attach_to_field = nil

  @split_file_name_on = Regexp.new(/\s+/)

  @missing_records = []
end

Instance Attribute Details

#attach_to_fieldObject

Returns the value of attribute attach_to_field.



19
20
21
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 19

def attach_to_field
  @attach_to_field
end

#attach_to_find_by_fieldObject

Returns the value of attribute attach_to_find_by_field.



19
20
21
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 19

def attach_to_find_by_field
  @attach_to_find_by_field
end

#attach_to_klassObject

Returns the value of attribute attach_to_klass.



19
20
21
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 19

def attach_to_klass
  @attach_to_klass
end

#loading_files_cacheObject (readonly)

Returns the value of attribute loading_files_cache.



24
25
26
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 24

def loading_files_cache
  @loading_files_cache
end

#missing_recordsObject (readonly)

Returns the value of attribute missing_records.



24
25
26
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 24

def missing_records
  @missing_records
end

#split_file_name_onObject

We try splitting up inbound file_names in various ways looking for the attachment Owner



22
23
24
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 22

def split_file_name_on
  @split_file_name_on
end

Instance Method Details

#find_bindingsObject



77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 77

def find_bindings
  # Map field to a suitable call on the Active Record Owner class e.g Owner.digitals
  bindings = begin
    logger.info("Finding matching field/association [#{attach_to_field}] on class [#{attach_to_klass}]")

    binder.map_inbound_fields(attach_to_klass, attach_to_field)
  rescue StandardError => e
    logger.error("Failed to map #{attach_to_field} to database operator : #{e.inspect}")
    logger.error( e.backtrace )
    raise MappingDefinitionError, 'Failed to map #{attach_to_field} to database operator'
  end

  bindings
end

#find_owner(in_file_name, options = {}) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 92

def find_owner(in_file_name, options = {} )

  search_term = File.basename(in_file_name, '.*')
  search_term.strip!

  logger.info("Attempting to find attachment owner (#{attach_to_klass} for [#{search_term}]")

  owner_record = get_record_by(attach_to_klass, attach_to_find_by_field, search_term, split_file_name_on, options)

  if owner_record
    logger.info("#{owner_record.class} (id : #{owner_record.id}) found with matching :#{attach_to_find_by_field} ")
  else

    message = "No matching owner found for file name : #{search_term}"

    failed = FailureData.new(nil, doc_context.node_context, message)

    doc_context.progress_monitor.failure(failed)

    missing_records << in_file_name
  end

  owner_record
end

#init(attach_to_klass, attach_to_find_by_field, attach_to_field, options = {}) ⇒ Object

> :attach_to_klass

  A class that has a relationship with the attachment (has_many, has_one or belongs_to etc)
  The instance of :attach_to_klass can be searched for and the new attachment assigned.

Examples
  Owner has_many pdfs and mp3 files as Digitals .... :attach_to_klass = Owner
  User has a single image used as an avatar ... :attach_to_klass = User

> :attach_to_find_by_field

  Field on the :attach_to_klass, this is the field used to search for the
  object (class == attach_to_klass) to assign the new attachment to.

Examples
  Owner has a unique 'name' field ... :attach_to_find_by_field = :name
  User has a unique  'login' field  ... :attach_to_klass = :login

> :attach_to_field

 Attribute/association to assign attachment to on :attach_to_klass.
Examples

   :attach_to_field => digitals  : Owner.digitals = attachment
   :attach_to_field => avatar    : User.avatar = attachment


61
62
63
64
65
66
67
68
69
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 61

def init(attach_to_klass, attach_to_find_by_field, attach_to_field, options = {})

  @attach_to_klass = MapperUtils.ensure_class( attach_to_klass )

  ModelMethods::Manager.catalog_class(@attach_to_klass, reload: options[:reload], instance_methods: true)

  @attach_to_find_by_field = attach_to_find_by_field
  @attach_to_field = attach_to_field
end

#init_from_options(options) ⇒ Object



71
72
73
74
75
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 71

def init_from_options(options)
  init(options[:attach_to_klass], options[:attach_to_find_by_field], options[:attach_to_field])

  @split_file_name_on = options[:split_file_name_on] if(options[:split_file_name_on])
end

#perform_load(options = {}) ⇒ Object

This version creates attachments and also attaches them to instances of :attach_to_klazz

Each file found in PATH will be processed - it’s file_name being used to scan for a matching record to attach the file to.

Options

:add_prefix


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/datashift/loaders/paperclip/attachment_loader.rb', line 125

def perform_load(options = {} )

  raise 'The class that attachments belongs to has not been set (:attach_to_klass)' unless @attach_to_klass

  raise "The field to search for attachment's owner has not been set (:attach_to_find_by_field)" unless @attach_to_find_by_field

  is_dummy_run = DataShift::Configuration.call.dummy_run

  @missing_records = []

  @load_object = options[:attachment] if options[:attachment]

  # Support both directory and file
  @loading_files_cache = DataShift::Paperclip.get_files(file_name, options)

  logger.info("Found #{loading_files_cache.size} files - splitting names on delimiter [#{split_file_name_on}]")

  # Map field to a suitable call on the Active Record Owner class e.g Owner.digitals
  bindings = find_bindings

  attach_to_method_binding = if bindings.size != 1
                               logger.warn("Failed to map #{attach_to_field} to database operator")
                               nil
                             else
                               bindings[0]
                             end

  # Iterate through all the files creating an attachment per file

  loading_files_cache.each do |in_file_name|
    attachment_name = File.basename(in_file_name)

    logger.info "Processing attachment file #{attachment_name} "

    owner_record = find_owner(in_file_name, options)

    # Don't actually create/upload to DB if we are doing dummy run
    # Don't create the Attachment if the Owner was not found

    next if(is_dummy_run || owner_record.nil?)

    attachment = create_paperclip_attachment(load_object_class, in_file_name, options)

    # Check if attachment must have an associated owner_record
    next unless attachment && owner_record && attach_to_method_binding
    reset

    # TOFIX - what about has_one etc ? - indicates that Context etc are still too complex and Excel/CSV focused
    owner_record.send(attach_to_method_binding.operator) << attachment

    logger.info "Added Attachment to #{owner_record.class} (id : #{owner_record.id})"
  end

  process_missing_records( missing_records )

  created = loading_files_cache.size - missing_records.size

  puts "Created #{created} / #{loading_files_cache.size} attachments of type #{load_object_class} attached to #{@attach_to_klass}"

  puts 'Dummy Run Complete - if happy run with full commit' if(is_dummy_run)

end