Salesforce Integration with Rails — Part 1

Rutvij
5 min readAug 2, 2017

--

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.

setup page

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_lead
privatedef 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.

--

--