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)