Force.com REST API Integration to push data to salesforce
This article is the first part of Salesforce Integration series and it focuses on Salesforce’s Force.com REST API integration, to push data from application to salesforce, with Rails (4.2) application.
In this article, we’re going to cover below topics -
- Setup Developer edition account
- Get Salesforce application credentials
- Create Rails application
- Force.com REST API Integration using restforce gem
Sample App
Setup Developer edition account
Use https://developer.salesforce.com/signup link to get your developer edition account. Developer edition account comes with only one environment — production. It does not feature Sandbox or Test environment.
To use REST API to integrate account with an application, the “API Enabled” permission must be enabled for your Developer Edition account. This permission is enabled by default.
After completing Signup, login to your account. Next, you need Consumer Key, Consumer Secret & Security token
Get Salesforce application credentials
To create an app, go to “Setup”, navigate to Build > Create > Apps and click on “New” button provided under “Connected Apps” section. Fill up the form and submit.
Once app gets created, it will give you Consumer Key & Consumer Secret. Copy them in a text file, we’ll need them later for API integration.
For Security token, navigate to My Settings > Personal > Reset My Security Token and click on “Reset Security Token”. This will send you security token on your registered mail id.
Create Rails application
Awesome! We’ve got everything we need for integration. Let’s go ahead and create a Rails application.
$ rails new salesforce_integration -d mysql
Brief about application functionality -
- Use Devise to set up user Registration and Profile update functionality
- Use Delayed-Job to perform Salesforce REST API call in background
- When a new user registers, send user’s details to Salesforce to generate a business Lead (Leads is a default object of Salesforce platform).
- If user updates profile details and Lead in Salesforce is still Open or not Converted/Closed, send updated details to Salesforce to update relevant Lead.
Configuring Devise & Delayed-Job gems in Rails application is out the scope of this article. Hence, kindly visit homepage of relevant gem if you need any help with configuring any of these gems in your rails application.
In sample application, a registration form looks like below which has some custom fields added with default fields provided by devise.
Generate a model named Lead to store details about Salesforce Lead object.
$ rails g model lead salesforce_id:string status:integer
Now, run the migration
$ rake db:migrate
Add below code in app/model/lead.rb file
belongs_to :userenum status: [:open_not_contacted, :working_contacted, :closed_converted, :closed_not_converted]
Force.com REST API Integration using restforce gem
Install gem restforce
Gemfile
gem 'restforce', '~> 2.5.3'
Run command
$ bundle install
Create a new .yml file to store salesforce account credentials
config/salesforce.yml
common: &common
api_version: '39.0'
username: '<username>'
password: '<password>'
security_token: '<security_token>'
client_id: '<client_id>'
client_secret: '<client_secret>'
# host: 'test.salesforce.com'
test:
<<: *common
development:
<<: *common
production:
<<: *common
You do not need to specify host in credentials for developer edition account
Developer Edition accounts do not have access to Sandbox (test.salesforce.com).
The default host is ‘login.salesforce.com’
You can connect to sandbox by specifying a host. Sandbox is available depending on which edition you have.
To load salesforce account credentials for relevant environment,
Add a file config/initializers/load_configuration.rb
require 'erb'
SALESFORCE = YAML.load(ERB.new(File.read(Rails.root.join("config","salesforce.yml").to_path)).result)[Rails.env]
Create a directory named salesforce under lib & config folders
Add a file lib/salesforce/base.rb
require 'restforce'
module Salesforce
class Base
include Salesforce::Util
def initialize
@client = Restforce.new :username => SALESFORCE["username"],
:password => SALESFORCE["password"],
:security_token => SALESFORCE["security_token"],
:client_id => SALESFORCE["client_id"],
:client_secret => SALESFORCE["client_secret"],
:api_version => SALESFORCE["api_version"] @client.authenticate!
end
end
end
In Salesforce::Base class we’ve included Salesforce::Util module. This module stores common methods used across Salesforce integration functionality.
Create a file lib/salesforce/util.rb
module Salesforce::Util
LOAD_FILEDS_MAPPING = Proc.new { |file_name| YAML.load_file(Rails.root.join("config", "salesforce", "#{file_name.downcase}.yml")) }
PARSER = Proc.new do |fields_map, entity_hash|
entity_hash = entity_hash.with_indifferent_access
fields_map.inject({}) {|result, (key_field, val_field)| (entity_hash[key_field].present? ? result[val_field.to_sym]= entity_hash[key_field] : nil) ; result}
end
def self.included(base)
base.extend(ClassMethods)
end
## Instance methods
def load_fields_map(file_name)
LOAD_FILEDS_MAPPING.call(file_name)
end
def parse_fields_map(fields_map, entity_hash)
PARSER.call(fields_map, entity_hash)
end
## Class methods
module ClassMethods
def load_fields_map(file_name)
LOAD_FILEDS_MAPPING.call(file_name)
end
def parse_fields_map(fields_map, entity_hash)
PARSER.call(fields_map, entity_hash)
end
end
end
Create a file config/salesforce/lead.yml to define fields mapping between Rails application’s database fields and Lead object’s fields in salesforce
config/salesforce/lead.yml
# db_field_name: sf_field_name
salesforce_id: Id
company: Company
first_name: FirstName
last_name: LastName
email: Email
phone: Phone
status: Status
Create a file lib/salesforce/lead.rb
module Salesforce
class Lead < Base
attr :fields_map
SF_OBJ_NAME = "Lead"
def initialize
super()
@fields_map = load_fields_map(SF_OBJ_NAME)
end
end
end
To push data to salesforce, we’ll need to use create & update APIs. Add below code in lib/salesforce/base.rb so that it can be used to create/ update all types of different objects in salesforce
def create(sf_object, fields_map, entity_hash)
@client.create!(sf_object, parse_fields_map(fields_map, entity_hash))
end
def update(sf_object, fields_map, entity_hash)
@client.update(sf_object, parse_fields_map(fields_map, entity_hash))
end
Method parse_fields_map is defined in Salesforce::Util module that processes hash comprising database fields-values map and generates salesforce fields-values mapping that can be passed to REST API
Create a delay job to create/update Salesforce Lead object. Run command -
$ rails g job salesforce_lead
Add below code in app/jobs/salesforce_lead_job.rb file created by executing above command
class SalesforceLeadJob < Struct.new(:user_id)
def perform
user = User.select("id, first_name, last_name, email, phone, company").where(id: user_id).first
sf_obj = Salesforce::Lead.new
if user.lead.present?
# update data in Salesforce only if Lead is still Open
# do not update data once lead gets converted/ cancelled
if user.lead.is_open?
entity_hash = user.attributes.merge(salesforce_id: user.lead.salesforce_id)
sf_obj.update(Salesforce::Lead::SF_OBJ_NAME, sf_obj.fields_map, entity_hash)
end
else
user.build_lead(status: Lead.statuses["open"]).save!
# Push data to Salesforce
sf_lead_id = sf_obj.create(Salesforce::Lead::SF_OBJ_NAME, sf_obj.fields_map, user.attributes)
# Update DB entry with Salesforce Lead ID
Lead.where(user_id: user.id).update_all(salesforce_id: sf_lead_id)
end
end
def max_attempts
3
end
def failure
## TODO - Send failure notification mail
end
end
Create after_save callback method in user.rb to enqueue SalesforceLead job whenever a new user registers or a current user updates profile details.
Add below code in app/models/user.rb
has_one :lead
after_save :create_update_leadprivatedef create_update_lead
if (self.changed & [“first_name”, “last_name”, “company”, “email”, “phone”]).present?
Delayed::Job.enqueue(SalesforceLeadJob.new(id))
end
end
Run your rails application
$ rails s
Run delayed job in another terminal window
$ rake jobs:work
Register a new user and wait for delayed job to execute. Once job gets processed successfully, you should be able to see your first Lead object created in your salesforce account.