I have been working with a customer who requires the ability to make a particular record private depending on a certain field. The first thing that came to mind was sharing the record using Apex. Jesse Lorenz put together a great article on how to work with Managed Sharing, and is a great place to start if you are considering using this feature of the platform.

When I look at customer requirements, I like to consider the business implications first (architecture after all, is the scaffolding behind the scenes of the business), and Managed Sharing has one critical aspect worth noting. As Jesse's article highlights:

"Record-level sharing settings can only be used to grant more permissive access to records. Record-level sharing settings cannot be used to restrict access to records."

This statement is critically important, and needs to be considered before anything is done. For my current project, this meant that all records must start out Private and, if a particular field is set, I need to open up the permissions. 

Notice, how this is the absolute opposite of the statement I started this entry with?  The Business requirement is the same, but the implication is very different. The unspoken implication here is that if I want to make my record public, I need a group to assign the sharing rules too. Group members should should consist of all the users that have access to the record if field X is checked. (Another best practice here is that you should always clearly understand what 'public' means to your business)
Now with a more clear understanding of the real business impact, I can start designing my Apex Trigger:

Trigger ManageSharingOnMyObject on My_Object__c (after insert, after update) {

List<My_Object__Share> myObjShares = new List<M_Object__Share>();

for(My_Object__c myobj : trigger.new)

{

//if it is private only share with my manager

if(myobj.is_Private__c)

{

My_Object__Share mgrShare = new  My_Object__Share();

//populate the share record with the ID of the record to be shared

mgrShare.ParentId = myobj.Id;

//now share with the users manager

mgrShare.UserOrGroupId = myobj.CreatedBy.ManagerId;

//options are edit,read, or all

mgrShare.AccessLevel = 'edit';

mgrShare.RowCause = Schema. My_Object__Share.RowCause.Manager_Access__c;

//add the share

myObjShares.add(mgrShare);

}

else  //share with everyone

{

My_Object__Share allShare = new  My_Object__Share();

//populate the share record with the ID of the record to be shared

allShare.ParentId = myobj.Id;

allShare.UserOrGroupId = 12345679;

}

}

if(! myObjShares.isEmpty())

{

// Insert all of the newly created Share records and capture save result 

    Database.SaveResult[] tripShareInsertResult = Database.insert(tripShares,false);

  //exception handling etc, omitted for brevity

   }

}


That's it. Our sharing rule is done, and we have clearly understood the business implications of such a change, and written our code to align correctly. 

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS