[SalesForce] Remote action problem

I'm working on a community site function which allows external users to self register, & I'm calling the Apex method with @RemoteAction via Visualforce.remoting.Manager.invokeAction.

In the method, I first insert a new record into Account, then call the Site.createExternalUser API to create the User record, which also creates a record into Contact. I need to also insert data into certain fields in Contact (e.g. Email) but the API does not allow me to do so, so I need to explicitly retrieve the Contact record inserted by the API & then update those fields.

When I define my controller as "public with sharing", the method works if I call it directly from VF page, but when called via remote action, the part that selects the Contact record always gives me "List has no rows for assignment to SObject" error. But when I check in Developer Console with the accountId returned for the Account record that I inserted, the Contact record can be retrieved without any issue. In fact, in the remote action method, even selecting Account or User object also gives me no row (even without any where condition).

But when I change my controller to "public without sharing", then everything works fine. Unfortunately, the code scanning engine that we are using classifies this approach as "blocker" & says that "With Sharing should be used on classes that make use of DML", so we cannot use it.

Anyone has any idea why this is happening to remote action? Any way to make it work without using "public without sharing"?

Best Answer

The reason this behaves differently is tied to the fact that you're Unauthenticated and logged in as "Guest" - The Remote Action is running as a separate session and for the purposes of the SOQL, it looks like another user.

Workarounds: 1) Stop using Site.createExternalUser - refactor the implementation to use Site.createPersonAccountPortalUser instead. The Person account's email address will be populated and there will be no need to do separate DML.

2) Move just the RemoteAction implementation from the Controller to another class leaving the implementation as-is. Keep "with sharing" on the Controller, get an exception to allow "without sharing" on the RemoteAction class.

3) Dumb down the UX by converting that action from a Remote Action (ajax-style) to a Command button that submits the Action for the page. This will keep it in a single session.

Related Topic