Blogs from the Ranch

< Back to Our Blog

Synchronizing SalesForce and Ruby on Rails



Salesforce, the large Customer Relationship Management tool, and Ruby on Rails, the elegant web development framework, seem like an awkward pair. About as awkward as dipping a Wendy’s french fry in a frosty.

Salesforce is large, often times confusing, and is a tool built for handling lots of different jobs. Rails is lean, elegant, and designed specifically for making web development easier. While Salesforce and Rails are dramatically different, they actually work very well together (much like a Wendy’s french fry dipped in a frosty – trust me).

This unlikely pairing is sparked by ActiveSalesforce, a Ruby on Rails connection adapter to Salesforce-managed data. This Ruby Gem makes working with Salesforce data about as easy as the Rails-MySQL combination.

Highgroove Studios is working on a Salesforce-Rails application, and one of the things we have to do is synchronize a local MySQL database with Salesforce. This is needed because the connection to Salesforce is slower than when working with a local database, and several parts of the application are time-sensitive.

Here’s a look at how we designed the application to synchronize data between the local database and Salesforce.

1. Abstract behaviors specific to Salesforce classes to a SalesforceRecord class.

    class SalesforceRecord < ActiveRecord::Base   self.abstract_class = true
  1. the salesforce database specified in database.yml
    self.establish_connection :salesforce

2. Abstract behaviors for local representations of the Salesforce classes to an Acts::As::Syncable module. We’ll use meta programming to add this module’s functionality to our local classes.

    # This module adds behaviors for syncing a local record  # with a Salesforce record. module ActiveRecord   module Acts #:nodoc:     module Syncable #:nodoc:       def self.included(base)         base.extend(ClassMethods)         end              module ClassMethods          # Use this method inside an ActiveRecord class           # to add this module's behaviors.           # Options:          #    - :with => Name of the native Salesforce           #               class that this class is synced with.           #               Ex: sync :with => Contact          #               Syncs this class with the +Contact+ class.          def sync(options = {})             write_inheritable_attribute(:sync_options, {               :with => options[:with]             })              class_inheritable_reader :sync_options                          include ActiveRecord::Acts::Syncable::InstanceMethods                   end       end              module InstanceMethods                                                   end # InstanceMethods     end # Syncable   end # Acts end # ActiveRecord


    require 'acts_as_syncable' ActiveRecord::Base.send(:include, ActiveRecord::Acts::Syncable)
    class Sfcontact < ActiveRecord::Base   sync :with => Contact end

3. Add a method to send local updates to Salesforce.

When a Sfcontact logs in to our Rails application, we want to update the last login time in both the local and Salesforce database.

    # Updates the +attribute+ and value of the local and does the same  # for associated record in the Salesforce database if the  # +sync :with+ option is provided.  # No exceptions are raised if the connection to Salesforce can't  # be established.         def update_attribute_and_sync(attribute,value)           if update_attribute(attribute,value)             synced_class = sync_options[:with]                          # only sync if a Salesforce class is provided             if synced_class.nil?               raise "Can't sync with a Salesforce record unless                       it is specified with the sync :with option."             # Turn into a Class if a String is passed             elsif synced_class.is_a? String               synced_class = kloned_class.constantize             end                          # updated the synced attribute...             # if we can't connect, don't raise an exception.             begin               synced_class.find_by_id(id).update_attribute(attribute,value)             rescue SocketError               logger.warn("Unable to connect to Salesforce and update                        [#{synced_class}] attribute [#{attribute}]                            with value [#{value}]")             end           end                                           end # update_attribute_and_sync

Here’s how we update both the local database and Salesforce:


Now we can synchronize and update from our local database to Salesforce by just adding a single line of code to our cloned Salesforce ActiveRecord classes.



Not Happy with Your Current App, or Digital Product?

Submit your event

Let's Discuss Your Project

Let's Discuss Your Project