Wednesday, August 20, 2014

Close recurring tasks using Apex

At least one developer had reported encountering an error when trying to automate updates to Task records using Apex: System.UnexpectedException: Apex Task trigger cannot handle batch operations on recurring tasks. This error occurs even in simple scenarios, such as simply closing any open tasks on a close opportunity.

While I agree with what I imagine to be general consensus that this error seems crazy, luckily there appears to be a workaround: Update a custom flag using Apex, and then use workflow rules to handle the dirty work of updating restricted standard field(s).

While I've only tested this approach on the scenario below, I think it will be applicable to solving other similar problems with updating Task records using Apex.

Sample solution to close recurring tasks using Apex


The anonymous Apex code below illustrates the solution.


And there's nothing special about the checkbox field, the workflow rule or the field update. The idea is that when the checkbox is checked, the workflow rule fires and performs the field update.


Friday, August 8, 2014

Created By and Last Modified By not set before insert or update

After some frustrating troubleshooting of what I thought would be simple code today, I learned something unexpected: Created By and Last Modified By are not populated or set in the before context of DML operations. This means that before insert, CreatedById, CreatedDate, LastModifiedById and LastModifiedDate are all empty. And before update, LastModifiedById and LastModifiedDate will reflect the previous person to modify the record, not the current user (which would be yourself if you are the one editing the record).

While this was counter-intuitive at first, I came to realize that there's no need to rely on those fields in the context of Apex triggers. All I really need is UserInfo.getUserId() and DateTime.now() to get the time.

Just like that... I learned something new today.

Tuesday, August 5, 2014

Person Accounts ignore Contact workflow rules and triggers

Every once in a while I find myself discussing the pros and cons Person Accounts, and inevitably a question comes up about how Account and Contact workflow rules and triggers are impacted. The vague statement that precipitates the question usually goes something like this, "Turning on Person Accounts creates problems for existing workflow rules and triggers." Today I finally decided to explore the validity of this statement myself, and the results were... well, disappointing.

The good news is that turning on Person Accounts will not break any of your existing functionality regarding Business Accounts and Contacts, as long as your Apex code is not automatically creating Contact records for accounts to emulate a one-to-one Account-Contact model.

The bad news is that none of your Contact workflow rules and triggers will fire for Person Account records. To me, this is a problem and poor design of the Person Accounts feature. Admins should at least be given the option to configure, perhaps via a checkbox, whether Contact workflow rules and triggers will fire for Person Account records. But as it currently stands, all benefits from existing Contact workflows and triggers are lost for person accounts.

If you agree with why the above bad news is bad, please promote this idea, "Person Accounts to work with Contact workflows and triggers." And read on if you want to know how I arrived at the above conclusions, which were tested in an Enterprise Edition org with Person Accounts enabled.

Test Setup (Summer '14)


The tests makes use of the following Text fields, for which history tracking is turned on:

  • Account Trigger Message (Account field)
  • Account Workflow Message (Account field)
  • Contact Trigger Message (Contact field)
  • Contact Workflow Message (Contact field)
To interact with those fields, we'll create two triggers and two workflow rules that simply set values for the implied fields on the Account and Contact object.
  • SetAccountTriggerMessage (Account trigger)
  • Set Account Workflow Message (Account workflow rule)
  • SetContactTriggerMessage (Contact trigger)
  • Set Contact Workflow Message (Contact workflow rule)
Now, with the stage set, let's move on to the tests.

Test 1: Create a person account


What happens when we create a person account?  Account workflow rules and triggers fire, but Contact workflow rules and triggers do not.

Test 2: Update an Account-only field on the person account


What happens when we update the Website field? Account workflow rules and triggers fire, but Contact ones do not.

Test 3: Update a Contact-only field on the person account


What happens when we update the Birthdate field? Oddly enough, Account workflow rules and triggers fire, but Contact ones do not.

Test 4: Update a special Account-Contact field on the person account


Knowing that the Account Name is linked to First Name and Last Name for Person Account records, what workflows and triggers will fire when you edit First Name or Last Name? Once again, Account workflow rules and triggers fire, but Contact ones do not.

Workaround for Contact workflows and triggers


The only supportable way to get Contact workflows and triggers to fire for Person Account records seems to be to recreate those workflows and triggers on the Account object. Whether this workaround is a pro or a con depends on your point of view. Obviously this creates more work and maintenance, but it allows for more granular and logical control over what happens with Contact fields for a person account vs. a regular contact.

Wednesday, July 9, 2014

XML Parsing Error: XML or text declaration not at start of entity

I'm not sure whether it's an XML specification requirement, but it appears that when rendering XML with Salesforce there cannot be any whitespace between the apex:page start tag and the first character.

The following code will work:


But the following code with visually pleasing indention will not:


If there are any unexpected spaces present after the apex:page start tag, you will likely encounter an error: XML Parsing Error: XML or text declaration not at start of entity


Monday, June 23, 2014

Faraday::SSLError certificate verify failed


Faraday::SSLError
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

In recent memory, this is easily the most frustrating error I've had to troubleshoot. I needed SSL to work so that I could establish secure communication between Salesforce and my Rails app on Heroku. Unfortunately, neither Heroku's sample Ruby (off Rails) app nor general OmniAuth documentation seemed to give any insight into the error or how to resolve it.

Piecing together bits of knowledge gleaned from Google searches, I eventually arrived at the following solution for Rails development on Windows 8:

  • Download root certificates in PEM format
  • Set an environment variable called CA_FILE, pointing to the downloaded PEM file
  • Create an omniauth.rb initializer file, as suggested by OmniAuth
  • Specify the :client_options hash value for the :salesforce provider, as shown below

I know I'm going to run into this error again in the future, and hopefully this blog post will help me and hopefully others resolve the problem in the most secure and supportable means available.

コンポーネントからページコントローラメソッドを呼ぶこと

初めて日本語でブログ投稿ですから、いろいろな文法的と文化的のミスしてしまって申し訳ありません。下記のコンテンツは「Controller Component Communication」の翻案です。

ある時にapex:Componentからページコントローラメソッドを呼ぶ必要が出て来ます。この場合で、ページコントローラをapex:attributeでコンポーネントコントローラに渡せば、以上の呼ぶことが出来てなります。

標準コントローラお使ってサンプルコードが提供されてお参照してください。サンプルコードはLeadCustomSaveページの作成方法です。


LeadCustomSave.page



ControllerHandleExtension.cls



CustomSave.component



CustomSaveController.cls


Wednesday, June 18, 2014

Rails directories for Heroku Connect

Heroku Connect is a new add-on offering that simplifies data synchronization between Heroku apps and Salesforce. At its core, Heroku Connect periodically syncs selected objects and fields between Salesforce and Heroku. While the demo Rails app provided by Heroku gives a solid recommendation for extending ActiveRecord::Base to create an analog for models in the Heroku Connect database, some gaps still existed in terms of how to best set up your Rails app and define your classes.

After some experimentation, I decided on the following setup for my app:

  • Heroku Connect model paths: app/models/heroku_connect/schema_name/table_name.rb
  • HerokuConnectRecord::Base
  • Autoload lib modules and classes

I'll explain the setup in more detail below, but quick question: How would you set up your Rails app directories for Heroku Connect?

Heroku Connect model paths


All models in your Rails app by default go in the app/models/ directory. Rails knows to autoload models stored in the models/ directory, and as a result it seemed to reason that Heroku Connect models should go in the same directory. But a namespace is needed to prevent conflicts between regular Rails models and Heroku Connect models. And moreover, what if you have multiple Heroku Connect databases in play?

My implementation addresses this by first moving Heroku Connect models into its own namespace a la the heroku_connect/ directory. Next, different Heroku Connect databases can be split by the schema name or some other unique identifier for each database.

Examples of Heroku Connect model class paths, assuming the schema name "salesforce"
sObject NameClass NameModel Path
Car__cHerokuConnect::Salesforce::Car__capp/models/heroku_connect/salesforce/car__c.rb
OpportunityLineItemHerokuConnect::Salesforce::OpportunityLineItemapp/models/heroku_connect/salesforce/opportunity_line_item.rb
AssessmentPeriod__cHerokuConnect::Salesforce::AssessmentPeriod__capp/models/heroku_connect/salesforce/assessment_period__c.rb

Note: For custom object models, the double-underscores can be written as-is in the name of the .rb file. To be more technical, use the String.underscore method in irb to derive the expected name of the model's .rb file. For example, JointVenture__c would become "joint_venture__c.rb", and Lazy_Boy__c would become "lazy_boy__c.rb".

HerokuConnectRecord::Base


Heroku recommends extending ActiveRecord::Base to create a base for all Heroku Connect models. I thought that instead of calling my base class SalesforceBase, I would call it HerokuConnectRecord::Base to be mimic the naming convention for ActiveRecord::Base. While there's no direct need for this to get going, I figured I would adopt this convention in case I need to extend other Active__ modules or classes down the road for Heroku Connect.

All that's needed to set up this class is the following code, placed within lib/heroku_connect_record/base.rb:

module HerokuConnectRecord
  class Base < ActiveRecord::Base
    self.abstract_class = true
    establish_connection ENV['DATABASE_URL']
  end
end

All Heroku Connect module classes would then extend this class, as in:

module HerokuConnect
  module Salesforce
    class Car__c < HerokuConnectRecord::Base
      self.table_name = "salesforce.car__c"
    end
  end
end

Autoload lib modules and classes


Finally, to autoload HerokuConnectRecord::Base (and potentially future custom classes for Heroku Connect), I adopted ifyouseewendy's recommendation to add the following line to config/application.rb:

config.autoload_paths += %W(#{config.root}/lib)