Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Visualforce Page for customizing Attachments. See UploadAttachmentController.
<apex:page standardController="Contact" tabStyle="Contact" extensions="UploadAttachmentController">
<apex:sectionHeader title="{!Contact.Name}" subtitle="Attach File"/>
<apex:form id="form_Upload">
<apex:pageBlock >
<apex:pageBlockButtons >
<apex:commandButton action="{!back}" value="Back to {!Contact.Name}"/>
<apex:commandButton action="{!back}" value="Cancel"/>
<apex:pageMessages />
<apex:pageBlockSection columns="1">
<apex:pageBlockSectionItem >
<apex:outputLabel value="File" for="file_File"/>
<apex:inputFile id="file_File" value="{!fileBody}" filename="{!fileName}"/>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Type" for="type"/>
<apex:selectList value="{!selectedType}" size="1" id="type">
<apex:selectOption itemValue="Plain ole awesome" itemLabel="Plain ole awesome"/>
<apex:selectOption itemValue="Super awesome" itemLabel="Super awesome"/>
<apex:selectOption itemValue="Most awesomest" itemLabel="Most awesomest"/>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Is the file awesome?" for="visible"/>
<apex:selectList value="{!selectedAwesomeness}" size="1" id="visible">
<apex:selectOption itemValue="false" itemLabel="No"/>
<apex:selectOption itemValue="true" itemLabel="Yes"/>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Description" for="description"/>
<apex:inputTextarea id="description" value="{!description}" rows="4" cols="50"/>
<apex:pageBlockSectionItem >
<apex:outputLabel value="" for="uploadBtn"/>
<apex:commandButton id="uploadBtn" value="Attach File" action="{!processUpload}" />
public class UploadAttachmentController {
public String selectedType {get;set;}
public Boolean selectedAwesomeness {get;set;}
public String description {get;set;}
private Contact contact {get;set;}
public String fileName {get;set;}
public Blob fileBody {get;set;}
public UploadAttachmentController(ApexPages.StandardController controller) { = (Contact)controller.getRecord();
// creates a new Contact_Attachment__c record
private Database.SaveResult saveCustomAttachment() {
Contact_Attachment__c obj = new Contact_Attachment__c();
obj.contact__c = contact.Id;
obj.description__c = description;
obj.type__c = selectedType;
obj.awesome__c = selectedAwesomeness;
// fill out cust obj fields
return Database.insert(obj);
// create an actual Attachment record with the Contact_Attachment__c as parent
private Database.SaveResult saveStandardAttachment(Id parentId) {
Database.SaveResult result;
Attachment attachment = new Attachment();
attachment.body = this.fileBody; = this.fileName;
attachment.parentId = parentId;
// inser the attahcment
result = Database.insert(attachment);
// reset the file for the view state
fileBody = Blob.valueOf(' ');
return result;
* Upload process is:
* 1. Insert new Contact_Attachment__c record
* 2. Insert new Attachment with the new Contact_Attachment__c record as parent
* 3. Update the Contact_Attachment__c record with the ID of the new Attachment
public PageReference processUpload() {
try {
Database.SaveResult customAttachmentResult = saveCustomAttachment();
if (customAttachmentResult == null || !customAttachmentResult.isSuccess()) {
ApexPages.AddMessage(new ApexPages.Message(ApexPages.Severity.ERROR,
'Could not save attachment.'));
return null;
Database.SaveResult attachmentResult = saveStandardAttachment(customAttachmentResult.getId());
if (attachmentResult == null || !attachmentResult.isSuccess()) {
ApexPages.AddMessage(new ApexPages.Message(ApexPages.Severity.ERROR,
'Could not save attachment.'));
return null;
} else {
// update the custom attachment record with some attachment info
Contact_Attachment__c customAttachment = [select id from Contact_Attachment__c where id = :customAttachmentResult.getId()]; = this.fileName;
customAttachment.Attachment__c = attachmentResult.getId();
update customAttachment;
} catch (Exception e) {
return null;
return new PageReference('/'+contact.Id);
public PageReference back() {
return new PageReference('/'+contact.Id);

This comment has been minimized.

Copy link

commented Aug 13, 2014

This is great! What would you suggest if someone needs to upload a new version? Delete and create new? Is there a way to utilize File feature which allows to upload multiple versions under the same record?


This comment has been minimized.

Copy link

commented Jan 6, 2015

Hello Jeff,

This customization is exactly what my organization needs in Salesforce. It’s a great workaround and I have set up the custom object, apex class and visualforce page in our sandbox environment. The one issue that I am running into is creating a test for the apex class that provides the necessary code coverage.

I have browsed through your site looking for the best ways to test the code you graciously provided and have been researching online for best practices on testing apex coding in general and have been coming up short. Could you please provide an additional demonstrate on how to test this specific custom code? Any additional assistance would be much appreciated.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.