Monthly Archives: June 2010

Dijon, France

Dijon is located in the Burgundy, France. It is a small town with 130,000 inhabitants. I spent 7 weeks learning French there. I had a fantastic time there. It was quite relaxing for me.

Using ActiveSalesForce Gem with ROR

I have been experimenting with the ActiveSalesForce plugin. The benefit of this plugin is that it provides a RubyOnRails (ActiveRecord) interface for retrieving Salesforce data using SOAP. However, the documentation for it is scant, meaning that one has to use the try-and-error method to find out what works and what does not work.

After searching online for a working tutorial, I finally found this one.

Most of that tutorial works fine. I like to add some more comments to it. As, it primarily showed the test cases with RFace and had a quick blur with the actual ActiveSalesforce Gem.

Basically, Activesalesforce gem sits on top of the RFace (which handles the communication for sending and receiving SOAP messages).

Step 1. install the Gem, which can be streamlined by inserting the following to the ‘config/environment.rb‘ file.

Rails::Initializer.run do |config|
  config.gem "althor880-activerecord-activesalesforce-adapter",
  :source => "http://rubygems.org", :lib => "activerecord-activesalesforce-adapter"
end

Step 2. run the following command to install the gem from the base-directory of the ROR app

$ sudo rake gems:install

Step 3, create the SfBase class, which should be inherited by all other ActiveSalesForce object.

$ ruby script/generate model Salesforce::SfBase

And, edit the class as:

class Salesforce::SfBase < ActiveRecord::Base
  self.abstract_class = true
  def self.login(user, pass, token)
    params = {:adapter => "activesalesforce",
              :url => "https://login.salesforce.com/services/Soap/u/19.0",
              :username => user,
              :password => pass + token
    }
    self.establish_connection(params)
  end

  set_table_name 'salesforce_sf_bases'
end

Step 4, generate other objects, e.g. ‘user‘, ‘account‘, and ‘contact‘.

$ ruby script/generate model Salesforce::User
$ ruby script/generate model Salesforce::Account
$ ruby script/generate model Salesforce::Contact

Step 5, complete the relationship of these classes.
Salesforce’s User model:

class Salesforce::User < Salesforce::SfBase
  has_many :contacts, :class_name => "Salesforce::Contact", :foreign_key => 'owner_id'
  has_many :accounts, :class_name => 'Salesforce::Account', :foreign_key => 'owner_id'
  set_table_name 'users'
  #table name must match the Salesforce, or it does not work. This is a quirk of the ActiveSalesforce
  #If you are using Hobo, which defaults to 'user' table for its object. You need to rename hobo user to use another table name. via "set_table_name 'hobo_users'" command.
end

Salesforce’s Contact model:

class Salesforce::Contact < Salesforce::SfBase
  #establish_connection(params)
  belongs_to :owner, :class_name => "Salesforce::User"
  set_table_name 'contacts'
  #table name must match the Salesforce, or it does not work. This is a quirk of the ActiveSalesforce'
end

Salesforce’s Account model:

class Salesforce::Account < Salesforce::SfBase
    belongs_to :owner, :class_name => "Salesforce::User"
    set_table_name 'accounts'
    #table name must match the Salesforce, or it does not work. This is a quirk of the ActiveSalesforce
end

Step 6, while ActiveSalesforce Gem wires the data-connection directly to SOAP, it is still a good practice to implement the database tables and complete the migration scripts.
SfBase migration script:

class CreateSalesforceSfBases < ActiveRecord::Migration
  def self.up
    create_table :salesforce_sf_bases do |t|

      t.timestamps
    end
  end

  def self.down
    drop_table :salesforce_sf_bases
  end
end

SfAccount migration script:

class CreateSalesforceAccounts < ActiveRecord::Migration
  def self.up
    create_table :accounts do |t|
      t.integer :owner_id
      t.timestamps
    end
  end

  def self.down
    drop_table :accounts
  end
end

SfUser migration script:

class CreateSalesforceUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end

SfContact migration script:

class CreateSalesforceContacts < ActiveRecord::Migration
  def self.up
    create_table :contacts do |t|
      t.integer :owner_id
      t.timestamps
    end
  end

  def self.down
    drop_table :contacts
  end
end

Step 7, build test cases:
‘test_helper.rb’ file:

ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help'
class ActiveSupport::TestCase
  self.use_transactional_fixtures = true
  fixtures :all
end
require 'keys'

‘keys.rb’ files -> username, password, security tokens: (separating the keys.rb files allows better control of version control, e.g. setting .gitignore on keys.rb file.)

# This file contains needed password, security token, and userid for testing
USERID ='userid@somewhere.email'
SECURITY_TOKEN ='security token'
PASSWORD ='pAssWorD'

SfBase test case:

require 'test_helper'
class Salesforce::SfBaseTest < ActiveSupport::TestCase
  # see test_helper for USERID, PASSWORD, and SECURITY_TOKEN
  def test_should_connect
    Salesforce::SfBase.login(USERID, PASSWORD, SECURITY_TOKEN)
    u = Salesforce::User.first
    assert_not_nil u
  end
end

SfUser test case:

require 'test_helper'
class Salesforce::UserTest < ActiveSupport::TestCase

  def test_should_return_sf_user
    # see test_helper for USERID, PASSWORD, and SECURITY_TOKEN

    Salesforce::SfBase.login(USERID, PASSWORD, SECURITY_TOKEN)
    #Salesforce::User.login(user, password, key)
    num_of_user = Salesforce::User.all.count
    puts "The number of users: " + num_of_user.to_s

    assert_not_nil num_of_user
    #u = Salesforce::User.first
    first_user = Salesforce::User.first
    puts "The first user is: " + first_user.first_name + " " + first_user.last_name
    assert_not_nil first_user
  end
end

SfAccount test case (showing both RFace and SalesForce A/R tests):

require 'test_helper'

class Salesforce::AccountTest < ActiveSupport::TestCase
  # see 'test_helper.rb' for USERID, PASSWORD, and SECURITY_TOKEN
  def test_find_accounts_with_rforce
    ##Test case with RFace
    @binding = RForce::Binding.new 'https://login.salesforce.com/services/Soap/u/19.0'

    @binding.login USERID, (PASSWORD + SECURITY_TOKEN)
    answer = @binding.search :searchString => "find {Arizona} in name fields returning account(id, phone)"
    assert_not_nil answer
  end

  def test_should_return_account
    # see 'test_helper.rb' for USERID, PASSWORD, and SECURITY_TOKEN
    Salesforce::SfBase.login(USERID, PASSWORD, SECURITY_TOKEN)
    user = Salesforce::User.first

    accounts = Array.new
    accounts = user.accounts

    #puts "The user {" +  user.first_name + " " + user.last_name + "} has " + user.accounts.size.to_s + " accounts."
    assert_not_nil accounts
  end

end

SfContact testcase:

require 'test_helper'

class Salesforce::ContactTest < ActiveSupport::TestCase
  def test_should_return_contacts
    # see 'test_helper.rb' for USERID, PASSWORD, and SECURITY_TOKEN
    Salesforce::SfBase.login(USERID, PASSWORD, SECURITY_TOKEN)
    user = Salesforce::User.first

    contacts = Array.new
    contacts = Salesforce::Contact.find(:all).count
    assert_not_nil contacts
  end

end

Note: if you call the following command ->  Salesforce:: (with find_by_xxxx), it will retrieve the model of the table.

>> Salesforce::User
=> Salesforce::User(id: text, username: text, last_name: text, first_name: text, name: text, company_name: text, division: text, department: text, title: text, street: text, city: text, state: text, postal_code: text, country: text, email: string, phone: string, fax: string, mobile_phone: string, alias: text, community_nickname: text, is_active: boolean, time_zone_sid_key: text, user_role_id: text, locale_sid_key: text, receives_info_emails: boolean, receives_admin_info_emails: boolean, email_encoding_key: text, profile_id: text, user_type: text, language_locale_key: text, employee_number: text, delegated_approver_id: text, manager_id: text, last_login_date: datetime, last_password_change_date: datetime, created_date: datetime, created_by_id: text, last_modified_date: datetime, last_modified_by_id: text, system_modstamp: datetime, offline_trial_expiration_date: datetime, offline_pda_trial_expiration_date: datetime, user_permissions_marketing_user: boolean, user_permissions_offline_user: boolean, user_permissions_call_center_auto_login: boolean, user_permissions_mobile_user: boolean, user_permissions_sf_content_user: boolean, user_permissions_knowledge_user: boolean, forecast_enabled: boolean, user_preferences_activity_reminders_popup: boolean, user_preferences_event_reminders_checkbox_default: boolean, user_preferences_task_reminders_checkbox_default: boolean, user_preferences_reminder_sound_off: boolean, user_preferences_disable_auto_sub_for_feeds: boolean, user_preferences_apex_pages_developer_mode: boolean, contact_id: text, account_id: text, call_center_id: text, extension: string, about_me: text, current_status: text)

SyntaxHighlighter Plugin


This shows how to use the SyntaxHighlighter Plugin.
1st, Java

function java_foo()
{
  if (counter <=10)
    return;
}

2nd, now Ruby

class Salesforce::SfBase < ActiveRecord::Base
  self.abstract_class = true
  def self.login(user, pass, token)
    params = {:adapter => "activesalesforce",
              :url => "https://login.salesforce.com/services/Soap/u/19.0",
              :username => user,
              :password => pass + token
    }
    self.establish_connection(params)
  end
end

To do it: first add the following HTML scripts:

<script type="text/javascript" src="js/shCore.js"></script>
<script type="text/javascript" src="css/shBrushJScript.js"></script>
<link href="css/shCore.css" rel="stylesheet" type="text/css" />
<link type="text/css" rel="Stylesheet" href="/styles/shThemeMidnight.css"/>

Add code into
[lang]
your code.
[/lang]

Finally, add

<script type="text/javascript">
     SyntaxHighlighter.all()
</script>