As developers working on a project, we often deal with integrating third party APIs, data storage, and business tools that are outside the scope of our applications. Salesforce provides a powerful business tool which is, more often than not, used by teams outside the development team.
One task we were recently presented with was to "Create a Rails application around a Salesforce workflow".
- Data can be entered from both the Rails app and from Salesforce
- There must be relatively low update times between both sets of data (a few minutes at most)
- Data integrity must be maintained
Enter Heroku Connect!
Heroku Connect makes it easy for you to build and deploy Heroku applications that share data with your Salesforce service. Using bi-directional synchronisation between Salesforce and Heroku Postgres, Heroku Connect syncs the data in your Postgres database with custom objects in your Salesforce database.
How it works
- Set up Heroku Connect
- Authenticate against your salesforce service
- Select objects and fields to expose
- No messy API calls (saves you having extra web workers)
- Work with salesforce data as if it were a regular Postgres database
- Customise sync frequency per Salesforce Object
- Resolve conflicts
The Rails side
Once you've set up Heroku Connect (it is recommended to use sandbox mode for staging and development), you'll be given a database URL and SCHEMA environment variables (this defaults to 'salesforce_' in most cases). Your application should reference these to allow for differences in config in Development, Staging and Production environments.
Your Salesforce models
Create a directory for your Salesforce namespace in app/models. Eg:
This directory will contain all our models that reference the Heroku Connect database.
It is recommended to create a base config file for the external connection to the Heroku Connect database.
# app/models/salesforce/base.rb class Salesforce::Base < ActiveRecord::Base self.abstract_class = true # this is not a real table # protect Salesforce defaults attr_protected :createddate, :systemmodstamp, :lastmodifieddate # optional: mark all records readonly - useful for test and development environments def readonly? true end # Point to Heroku Connect database # Use environment variables to separate dev, staging and production instances establish_connection ENV['HEROKUCONNECT_URL'] end
By setting up the
Salesforce::Base class we can then create other models which inherit from this, maintaining the base config and overwriting options as required.
# app/models/salesforce/customer.rb class Salesforce::Customer < Base # this will attempt to connect to salesforce_customers table in the Heroku Connect database # modify the expected table name if required self.table_name = 'customer_records' # ActiveRecord scopes, validations and associations # any other methods, overrides from base class etc ... end
The ActiveRecord you're familiar with!
Once everything is set up, we can now interact with our
Salesforce::Customer table using ActiveRecord.
Salesforce::Customer.where(age: 28) # this will work if the table is not readonly as in the previous example Salesforce::Customer.create(name: 'John Smith', age: 30, email: 'email@example.com')
Note: All Salesforce objects have a generated
sfid which is a global unique identifier generated by Salesforce. This is also used when viewing Salesforce associations and can be used within your models.
Validations are the best way to ensure data integrity. Whilst your ActiveRecord validations might allow a record to be saved, Salesforce objects may have a different agenda. Heroku Connect logs gives us a detailed list of events indicating whether records are successfully saved and synced, and descriptive errors to allow us to implement further business logic.
The source of truth
Upon commencing your Salesforce + Rails + Heroku Connect application, you'll need to work out where your source of truth lies. If the wider business is used to the Salesforce interface and inner workings, ensure that your application is built to accommodate the multiple data input sources.
Heroku Connect will sync your new and updated records in the background. Once you save a record, it may not appear in Salesforce immediately, although the feedback time is quite short (less than a minute). And, of course, we can still work with our newly persisted objects straight from the Postgres database.
It is recommended that extra security measures are put in place on the Salesforce side to ensure that data is not unintentionally deleted. Whilst we now have the ability to create records, the flip side is that we now have the ability to destroy them as well.
To reduce the risk, ask yourself how much of the data is required for your application? Working with a subset of data allows you to build a custom interface and scope your application to a specific business workflow.