1

I am new to Salesforce and should write a validation rule. I was asked to make sure a user who has modify all access on accounts (by default they would get edit access to Account name, Account owner and Account record type fields) to not to edit any other field other than one field he should. This is what I am using and is throwing me an error. But when i try to edit these fields on Account, even I am seeing this error. What is my mistake and how can it be corrected?

OR( 
ISCHANGED(OwnerId), 
ISCHANGED(Name), 
ISCHANGED(RecordTypeId), 
AND($User.Id= '005700000057vwa') 
)
6

In situations like the one that you're facing, I find it can be helpful to try to manually step through a process to try to understand what's going on.

I'm assuming that your user id isn't the one being restricted. For ease, let's pretend that your validation rule is currently this:

OR( 
    ISCHANGED(OwnerId), 
    ISCHANGED(Name), 
    ISCHANGED(RecordTypeId), 
    AND($User.Id= '005000000000123') 
)

and that your user id is 005000000000789

So, why is this validation rule preventing you from editing fields?

Say you've edited the record's name, and only the name. Let's step through the validation rule.

  • ISCHANGED(OwnerId), this statement is false, since we're only changing the name
  • ISCHANGED(Name), this statement is true
  • ISCHANGED(RecordTypeId), this statement is false
  • $User.Id = '005000000000123', since your user id is 005000000000789, this statement is false

Now that we've evaluated part of the statement, we can substitute statements for their values. In the eyes of Salesforce, your validation rule now looks like this1:

OR(
    false,
    true,
    false,
    AND(false)
)

AND()-ing a single term produces the same value as the term itself, so, simplifying a little bit, we get

OR(
    false,
    true,
    false,
    false
)

If any single condition in an OR() is true, the result is true. If a validation rule's formula ends up evaluating to true (as it does in the case when you, yourself, edit the Name field), then the validation rule steps in, displays its error message, and prevents the record change from happening.

Now that we know what went wrong, how do we make it work?

The short answer is, unsatisfyingly, you don't. Validation rules are meant to prevent people from putting a record into a state where some piece of data is bad.

Validation rules aren't the right tool to use to restrict access to fields. They can be used in very simple cases (i.e. prevent this user from editing this specific field). If the problem that you're trying to solve is "prevent x from editing any fields except fields x, y, z", then validation rules are of little help.

Instead of a validation rule, the tool I'd suggest using is profiles.

You can create a custom profile for this user, and give the profile permissions to create, read, and modify all Account records. After that, you can edit the Field-Level Security of the fields that you don't want this user to be able to edit to remove the edit permission for that one user profile (or more than one profile, if you're so inclined).

1: This isn't technically 100% true. Through my own testing that I did in writing one of my first answers on this site, Salesforce evaluates validation rules in a lazy fashion. That is, if we can get the result of a statement by only evaluating part of it, Salesforce will only do as much work as they need to to get the answer. In this particular case, the evaluation stops after evaluating ISCHANGED(Name). This is because, in boolean logic, inside an OR(), the whole thing will result in true once we find the first thing that evaluates to true. In reality, ISCHANGED(RecordTypeId) and AND($User.Id = 'value') aren't evaluated, because doing so would not change the result. The overall OR() function would still return true.

  • My vote for best written answer for this quarter goes to you Derek :) for this answer. – Rao Mar 31 '17 at 20:01
  • @Rao Thanks! Guess that means I should probably include the extra footnote that I was considering on adding. – Derek F Mar 31 '17 at 20:26
1

Best way to handle this to create a separate page layout and make all other fields as read only on the page layout.

Assign this page layout through the recordtype.

Otherwise, if you have 50+ fields on Account then you can't check field by field to verify if that has been modified in validation rule.

Also make sure this user doesn't have edit read only fields permission.

1

I totally would go with Derek's / Santanu's proposed solution if I were you.

But for the heck of it, I have created a trigger that can do what you need with your current setup.

Validation rule would be complex(not impossible if you start doing ISCHANGED(every_fieldname) in the object.

trigger disableUserEdit on Account (before update) {

    //Define the sobject.
    SObjectType accountType = Schema.getGlobalDescribe().get('Account');
    //Get all fields from account object.
    Map<String,Schema.SObjectField> AllfieldsMap = accountType.getDescribe().fields.getMap();

    //Create a map to hold the final set of fields to check.
    map<String,Schema.SObjectField> finalfieldset = new map<string,Schema.SObjectField>();

    //Create a set to hold the fields that the user can edit. Preferable to use custom label/setting instead of hardcoding values.
    //Only nasty part here is you make sure you use consistent case. you cannot do mixed case map keys are case sensitive. I get the key from map using lowercase hence popualted with lowercase in my set.
    set<string> fieldstheusercanedit = new set<string>{'ownerid','name','recordtypeid'};

    //Filter the fields the user can edit and add the rest to the final map
    for(string fieldname: AllfieldsMap.keyset()){
        if(!fieldstheusercanedit.contains(fieldname)){
            finalfieldset.put(fieldname, AllfieldsMap.get(fieldname.tolowercase()));
        }
    }

    //If the value on any of the other fields is changed by the user= 
        for(Account acc: trigger.new){
            for(string s: finalfieldset.keyset()){
                if(acc.get(s)!= trigger.oldmap.get(acc.Id).get(s) && userinfo.getUserId()== '005700000057vwa'){
                    acc.adderror('You can only modify Name, OwnerId and Recordtype on this object.');
                }

            }
        }
    }

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.