37

I run a query from an apex class (with sharing), and I get no results I can be sure the user doesn't have permissions (if I know otherwise that the records do exist).

But can I get this information without running a query?

I was thinking of the Share objects but I suppose they aren't created for manual and rule based sharing?

Edit: Why I want no query? Here's my real scenario. In a VF page displaying multiple records, I need to show an 'Edit' button against records for which the current user has edit permissions. My question should've been clearer; sincere apologies.

  • 1
    What information are you trying to get? A guarantee (or count) of how many records the user has permission to view? – Daniel Blackhall Aug 5 '12 at 23:59
58

To find out if a particular user has Edit access to a record, use the UserRecordAccess object. This object is available in API version 24.0 and later. You can use SOQL to query this object to find out if the user has edit access to the record in question.

SELECT RecordId, HasEditAccess FROM UserRecordAccess WHERE UserId = [single ID] AND RecordId = [single ID]

If you want to check a batch of records you can use

SELECT RecordId FROM UserRecordAccess WHERE UserId=:UserInfo.getUserId() AND HasReadAccess = true AND RecordId IN :allRecordIds LIMIT 200

But make sure that allRecordIds is a LIST of IDs. It doesn't work if allRecordIds is a SET of IDs. I guess that's a bug.

Also, only a maximum amount of 200 recordIds can be checked in one query.

  • Interesting, I didn't know this existed. Can you add the link to the documentation for UserRecordAccess to your answer as well? Was just having a random play with it and ran into the SOQL restrictions. E.g. "INVALID_FIELD: Can select only RecordID, a Has*Access field, and MaxAccessLevel". – Daniel Ballinger Aug 6 '12 at 20:49
  • 1
    I just edited the link into the answer, but I'm not sure when it will show up. Here it is, in any case: salesforce.com/us/developer/docs/api/Content/… – metadaddy Aug 6 '12 at 21:01
  • Thanks for the edit @metadaddy. I completely forgot the link. – Daniel Hoechst Aug 7 '12 at 2:31
  • 1
    "But make sure that allRecordIds is a LIST of IDs. It doesn't work if allRecordIds is a SET of IDs. I guess that's a bug." - That line just ended my hair pulling session. – Brad Ullery Apr 19 '13 at 18:19
14

Since API 30.0 you can query an object directly (see Checking for Object Accessibility):

SELECT Id, Name, UserRecordAccess.HasReadAccess, UserRecordAccess.HasTransferAccess, UserRecordAccess.MaxAccessLevel 
  FROM Account

It also works for custom object, but unfortunately it doesn't help myself since it doesn't seem to work for the Task object.

  • Check the answers that already have given and since there may be the accepted answer as well. Also it's good to check when the question has raised. BTW, it's good to help the community :) – highfive Apr 1 '14 at 9:52
  • 4
    It was meant as an expansion on the (perfectly acceptable) answer given. People looking for this issue might end up here (like I did) and might be interested in the API30 solution as well. – Marco Pietersen Apr 16 '14 at 12:45
  • I think this is a far better approach (for those object types for which it works) than the selected best answer because you are not limited to 200 objects; we have tested this and know it works with at least 1000 objects (if not more). BTW, I believe this provides a compound answer based on both profile CRUD permissions and sharing rules, but if someone knows better I would be interested to hear. – Phil W May 15 at 14:22
  • have you been able to find some way to get it working for Task? – zaitsman May 28 at 23:55
11

There is Checking for Object Accessibility that shows how to check for access at the object level.

In Visualforce:

{!$ObjectType.Account.accessible}

In Apex (see Understanding Apex Describe Information):

Schema.DescribeSObjectResult accountDescribe = Account.sObjectType.getDescribe();
System.debug('accessible:' + accountDescribe.accessible);

Beyond that, I suspect if you want to check at a per record level you won't be able to avoid the query.

I'm not very familiar with how the Apex managed sharing works, but from what I've read you would just be querying the related sharing object rather than the object in question.

  • 5
    I would agree that there is no way to check record accessibility without a query. Rather than querying the sharing, use a newer object: SELECT RecordId, MaxAccessLevel FROM UserRecordAccess WHERE UserId = [single ID] AND RecordId = [single ID]. You can see more about this object here: salesforce.com/us/developer/docs/api/Content/… – Daniel Hoechst Aug 6 '12 at 14:32
  • @DanielHoechst Can you put that as an answer. Sorry if my question wasn't clear. I wanted to avoid a query only because it'd throw a No rows for assignment exception.. – Vid L Aug 6 '12 at 17:30
  • 1
    @LVS Select into a list (rather than an object) and you won't get the 'no rows' exception. – metadaddy Aug 6 '12 at 17:54
  • @metadaddy yes I do that..more detail in the question's edit :) – Vid L Aug 6 '12 at 18:01
2

There are multiple programmatic ways of determining access. But a declarative method is to just click the Sharing button on the record and view the users who have access as well as why they have access by clicking the 'Why?' link?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.