class CouchrestAttachment
Converts from Tinkit
attachment format to closer to the metal couchrest/CouchDB attachment format. The reason this is needed is because CouchDB cannot support custom metadata for attachments. So custom metadata is held in the CouchrestAttachment
document. This document will also hold the attachments and its built in metadata (such as content-type and modified times
Attachment structure: attachments =>{ attachment_1 => { 'data1' => raw attachment data1, 'md1' => combined attachment metadata1 }, attachment_2 => { 'data2' => raw attachment data2, 'md2' => combined attachment metadata2 } }
Constants
- AttachmentID
changing this will result in existing persisted data being lost (unless the persisted data is updated as well)
- CouchDBAttachParams
CouchDB attachment metadata parameters supported by
CouchrestAttachment
Public Class Methods
# File lib/glue_envs/couchrest/couchrest_attachment_handler.rb, line 131 def self.add_attachment_package(doc_id, attach_class, attachments) raise "No class definition provided for attachments" unless attach_class raise "No id found for the document" unless doc_id #bufs_node._model_metadata[:_id] raise "No attachments provided for attaching" unless attachments att_doc_id = self.uniq_att_doc_id(doc_id) att_doc = self.get(att_doc_id) rtn = if att_doc self.update_attachment_package(att_doc, attachments) else self.create_attachment_package(att_doc_id, attach_class, attachments) end return rtn end
Create an attachment for a particular BUFS document
# File lib/glue_envs/couchrest/couchrest_attachment_handler.rb, line 146 def self.create_attachment_package(att_doc_id, attach_class, attachments) raise "No class definition provided for attachments" unless attach_class raise "No id found for the document" unless att_doc_id raise "No attachments provided for attaching" unless attachments sorted_attachments = CouchrestAttachmentHelpers.sort_attachment_data(attachments) custom_metadata_doc_params = {'_id' => att_doc_id, 'md_attachments' => sorted_attachments['cust_md_by_name']} att_doc = attach_class.new(custom_metadata_doc_params) att_doc.save sorted_attachments['att_md_by_name'].each do |att_name, params| esc_att_name = TkEscape.escape(att_name) att_doc.put_attachment(esc_att_name, sorted_attachments['data_by_name'][esc_att_name],params) end #returns the updated document from the database return self.get(att_doc_id) end
retrieves document attachments for a particular document
# File lib/glue_envs/couchrest/couchrest_attachment_handler.rb, line 222 def self.get_attachments(att_doc) return nil unless att_doc custom_md = att_doc['md_attachments'] esc_couch_md = att_doc['_attachments'] md_no_att = custom_md && !esc_couch_md att_no_md = esc_couch_md && !custom_md raise "DB Record corrupted? Attachment metadata exists,"\ " but no attachments for #{att_doc['_id'].inspect}" if md_no_att raise "DB Record corrupted? Attachments exist, but no metadata"\ " is associated with it for #{att_doc['_id'].inspect}" if att_no_md couch_md = CouchrestAttachmentHelpers.unescape_names_in_attachments(esc_couch_md) if custom_md.keys.sort != couch_md.keys.sort raise "data integrity error, attachment metadata inconsistency\n"\ "in memory: #{custom_md.inspect} \n persisted: #{couch_md.inspect}" end (attachment_data = custom_md.dup).merge(couch_md) {|k,v_custom, v_couch| v_custom.merge(v_couch)} end
create the attachment document id to be used
# File lib/glue_envs/couchrest/couchrest_attachment_handler.rb, line 127 def self.uniq_att_doc_id(doc_id) uniq_id = doc_id + AttachmentID if doc_id#bufs_node.class.attachment_base_id end
Update the attachment data for a particular BUFS document
Important Note: Currently existing data is only updated if new data has been modified more recently than the existing data.
# File lib/glue_envs/couchrest/couchrest_attachment_handler.rb, line 173 def self.update_attachment_package(att_doc, new_attachments) existing_attachments = att_doc.get_attachments most_recent_attachment = {} if existing_attachments new_attachments.each do |new_att_name, new_data| esc_new_att_name = TkEscape.escape(new_att_name) working_doc = att_doc.class.get(att_doc['_id']) if existing_attachments.keys.include? esc_new_att_name #filename already exists as an attachment fresh_attachment =self.find_most_recent_attachment(existing_attachments[esc_new_att_name], new_attachments[new_att_name]['md']) most_recent_attachment[esc_new_att_name] = fresh_attachment #re-add the if statement to prevent old from overwriting newer files ###if most_recent_attachment[esc_new_att_name] != existing_attachments[esc_new_att_name] #update that file and metadata sorted_attachments = CouchrestAttachmentHelpers.sort_attachment_data(esc_new_att_name => new_data) #update doc working_doc['md_attachments'] = working_doc['md_attachments'].merge(sorted_attachments['cust_md_by_name']) #update attachments working_doc.save #Add Couch attachment data att_data = sorted_attachments['data_by_name'][esc_new_att_name] att_md = sorted_attachments['att_md_by_name'][esc_new_att_name] working_doc.put_attachment(esc_new_att_name, att_data,att_md) ###else #do anything here? #puts "Warning, didn't update the attachment because current attachment is older than present one" ###end else #filename does not exist in attachment #puts "Attachment Name not found in Attachment Document, adding #{esc_new_att_name}" sorted_attachments = CouchrestAttachmentHelpers.sort_attachment_data(esc_new_att_name => new_data) #update doc working_doc['md_attachments'] = working_doc['md_attachments'].merge(sorted_attachments['cust_md_by_name']) #update attachments working_doc.save #Add Couch attachment data att_data = sorted_attachments['data_by_name'][esc_new_att_name] att_md = sorted_attachments['att_md_by_name'][esc_new_att_name] working_doc.put_attachment(esc_new_att_name, att_data,att_md) #working_doc does not have attachment end end end return att_doc.class.get(att_doc['_id']) end
Private Class Methods
# File lib/glue_envs/couchrest/couchrest_attachment_handler.rb, line 260 def self.find_most_recent_attachment(attachment_data1, attachment_data2) #"Finding most recent attachment" most_recent_attachment_data = nil if attachment_data1 && attachment_data2 if attachment_data1['file_modified'] >= attachment_data2['file_modified'] most_recent_attachment_data = attachment_data1 else most_recent_attachment_data = attachment_data2 end else most_recent_attachment_data = attachment_data1 || attachment_data2 end most_recent_attachment_data end
Public Instance Methods
retrieves document attachments for this document
# File lib/glue_envs/couchrest/couchrest_attachment_handler.rb, line 241 def get_attachments self.class.get_attachments(self) end
# File lib/glue_envs/couchrest/couchrest_attachment_handler.rb, line 245 def remove_attachment(attachment_names) attachment_names = [attachment_names].flatten attachment_names.each do |att_name| att_name = TkEscape.escape(att_name) self['md_attachments'].delete(att_name) self['_attachments'].delete(att_name) end resp = self.save atts = self.class.get_attachments(self) raise "Remove Attachment Operation Failed with response: #{resp.inspect}" unless resp == true self end