AngularJS and Salesforce.com Tutorial

June 10th, 2013

A couple of weeks ago I attend the Building Enterprise Apps Rapidly with Salesforce Mobile Packs webinar with Pat Patterson and Raja Rao. While I think it was a good introduction to AngularJS in general it seemed to lack any specific Force.com integration (probably by design). So for anyone looking to get started with AngularJS and Force.com I put together a small demo application that creates, updates and displays Account records from a Salesforce.com org. Feel free to clone the repo for your own use, learn from the code or pick it apart to make it better.

I personally like to see an application in action before I dive into the code, so you can run the application yourself at http://angularjs-salesforce.herokuapp.com. The code is hosted at github for your forking pleasure but we’ll walk through it in detail below.

The application is technically a Rails application but Ruby is only used for the CRUD operations with Salesforce.com. This eliminates the CORS issues with multiple domains. I used the awesome Restforce gem and expose everything as JSON in the controller. Perhaps a better, pure JavaScript solution would have been to use Node for the backend with the equally as awesome nforce package but I’ll leave that to another blog post. I started out using CoffeeScript but switched back to straight JavaScript as I think it is easier for most people to grok.

So let’s jump into the application. The github repo has the instruction for installing and running the application both locally and on Heroku. First get the application up and running and then continue reading below.

Let’s start with the Rails portion of the application since it is fairly simple. The routes.rb file simply declares our RESTful accounts resource (for communicating with Force.com) and directs all requests to the index route in the applcation controller. This route will start our Angular app for us.

1
2
3
4
AngularSalesforceDemo::Application.routes.draw do
  resources :accounts
  root to: 'application#index'
end

We need to add some Angular directives to our application.html.erb to make the application work. First, on line 2 we add ng-app=”app” to auto-bootstrap our application called (wait for it……) “app”! We also add ng-view to line 11 so that the view will change based upon the current route requested.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
  <title>AngularJS Salesforce Demo</title>
  <%= stylesheet_link_tag    "application", :media => "all" %>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>
</head>
<body>
<div class="container">
  <div ng-view="ng-view"></div>
</div>
</body>
</html>

Here is the ApplicationController that renders the single page for our application. We just need a place to launch from and this happens to be it. So we have no view (thus :nothing => true) but we still want the layout (since it has the app bootstrap code).

1
2
3
4
5
6
7
8
9
class ApplicationController < ActionController::Base
  protect_from_forgery
 
  # We'll just use this as a launch point for our App
  def index
    render :layout => 'application', :nothing => true
  end
 
end

Lastly is the workhorse of the application, the AccountController. This controller performs all of the interaction with Force.com using the Restforce gem (the private ‘client’ method on line #43) and is designed to only return JSON data. The code is commented below but there are actions to query for account records (index), return a specific account by id (show), create a new account in Salesforce.com (create) and update an existing account in Salesforce.com (update).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class AccountsController < ApplicationController
  respond_to :json
 
  def index
    # simply return the query as json
    respond_with client.query('select id, name, type, billingstate 
      from account order by lastmodifieddate desc limit 5')
  end
 
  def show
    # return the requested record as json
    respond_with client.query("select id, name, type, billingstate 
      from account where id = '#{params[:id]}'").first
  end	
 
  # create a new record in salesforce. Use the following command for testing:
  #   curl -v  -H "Content-type: application/json" -X POST 
  #     -d '{"name": "some test name"}' http://localhost:3000/accounts
  def create
    # create the account in salesforce and get the new id
    id = client.create!('Account', Name: params[:name], Type: 'Prospect', 
      BillingState: 'NY')
    # query for the newly created account
    account = client.query("select id, name, type from account 
      where id = '#{id}'").first
    # return the resource so it can be added to the collection
    respond_with(account, :status => :created, 
      :location => account_url(account))
  end		
 
  def update
    # update only two of the fields in salesforce and return the record
    client.update!('Account', Id: params[:account][:Id], 
      Name: params[:account][:Name], 
      Type: params[:account][:Type])
    respond_with client.query("select id, name, type, billingstate 
      from account where id ='#{params[:account][:Id]}'")
  end		
 
  private
 
    # define the restforce client and authenticate
    def client
      client = Restforce.new :username => ENV['SFDC_USERNAME'],
        :password       => ENV['SFDC_PASSWORD'],
        :client_id      => ENV['SFDC_CLIENT_ID'],
        :client_secret  => ENV['SFDC_CLIENT_SECRET'],
        :host           => ENV['SFDC_HOST']
      client.authenticate!
      client
    end
 
end

Now the fun stuff… AngularJS! This isn’t a “how to learn AngularJS” post so be sure to check out egghead.io and the AngularJS tutorial to really dig into the framework. There are four main parts of the app under the app/assets/javascripts/angular directory

The app.js file is the launcher for our entire application and defines our module called “app”. It contains our routing information which tells Angular which controller and view template to load based upon the route being requested (home page with the list of accounts or account details page). We also inject the ngResource dependency so that our application can take advantage of our RESTful resources in our rails controller.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'use strict';
/*
    This is our main launch point from Angular. We will put anything to do with the
    general well being of our app in this file. For now it will basically just contain
    the routing information.
 
    Our module will be called "app".
 */
angular.module('app', ['ngResource'])
  .config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
    $routeProvider
       .when('/', {
         controller: 'AccountListCtrl', 
         templateUrl: '/assets/angular/templates/index.html'
        })
       .when('/accounts/:id', {
         controller: 'AccountDetailCtrl', 
         templateUrl: '/assets/angular/templates/details.html'
       })
       .otherwise({redirectTo: '/'});
}]);

The services directory has a single models.js file which defines our Account resource to communicate with Force.com via the RESTful routes. We pass in the URL to the resource, “/accounts”, and an optional :id parameter. Angular will use the id parameter if present and call the show action in the controller, otherwise it will call the index route to return all accounts. Since, by default, the Angular $resource does not support an update method, we need to declare an additional action (i.e., update) that we can call on the Account resource.

1
2
3
4
5
6
7
'use strict';
 
var app = angular.module('app');
 
app.factory('Account', ['$resource', function($resource) {
  return $resource('/accounts/:id', {id: '@id'}, {update: {method: "PUT"}});
}]);

Since controllers and views work hand-in-hand, let take a look at them together as part of the route.

Home Page

When the user visits the root page in our application (i.e., “/”), Angular loads the AccountListCtrl controller and the index.html view template. In line #5 we inject the Account resource into our controller so that our RESTful routes are available. Line #6 defines a scope variable called “accounts” which contains an array of Accounts by returning ‘/accounts.json’ via Account.query().

We also define an “add” function that is used when the user submits the form to create a new Account. This function creates a new Account resource, calls $save on the resource (POSTs the data to our create action in our controller to insert it into Salesforce.com), adds the new Account resource to the array of all “accounts” and then clears out the form for reuse.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'use strict';
 
var app = angular.module('app');
 
app.controller('AccountListCtrl', function($scope, Account) {
  $scope.accounts = Account.query();
 
  $scope.add = function() {
    var account = new Account({name:$scope.newAccount.name});
    account.$save(function() {
      $scope.accounts.push(account)
      $scope.newAccount = {}
    });
  }  
});

In the index.html template, the ng-controller directive declares the controller to be used for the section of code (you can use multiple controllers in the same template). We first have a form that allows the user to add a new Account. The ng-submit directive defines the function in the controller to execute when the form is submitted. The ng-model directive tells Angular to do two-way data binding with our newAccount object so that it can easily be used in our controller.

Next we simply output our five Accounts from Salesforce.com using the ng-repeat directive.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<h1>AngularJS Demo with Salesforce.com</h1>
 
<span class="lead" style="padding-bottom:10px">By Jeff Douglas (<a href="http://www.twitter.com/jeffdonthemic" target="_blank">@jeffdonthemic</a>). You can find the accompanying blog post at <a href="http://blog.jeffdouglas.com/?p=4800" target="_blank">blog.jeffdouglas.com</a>. This demo connects to Salesforce.com using Ruby on Rails. The application allows you to create, update and display Account records from Salesforce.com.</span>
 
<div ng-controller="AccountListCtrl">
 
  <h2>Create a New Account</h2>
  <form name="frm" ng-submit="add()">
    <input type="text" class="input-xlarge" ng-model="newAccount.name" required><br/>
    <button type="Submit" class="btn btn-primary">Add Account</button>
  </form><br/>
 
  <h2>Last 5 Modified Accounts</h2>
 
  <table class="table table-striped">
  <thead>
    <tr>
      <th>Account Name</th>
      <th>Type</th>
      <th>State</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="account in accounts">
      <td><a href="#/accounts/{{account.Id}}">{{account.Name}}</a></td>
      <td>{{account.Type}}</td>
      <td>{{account.BillingState}}</td>
    </tr>
  </tbody>
  </table>
 
</div>

Account Details & Edit Page

The final part of our application is the account details page. The AccountDetailCtrl controller is loaded and the details.html template is displayed when the details route (/accounts/:id) is requested. This page has a little more going on as it not only displays the details of the page but also provides the functionality for updating the Account in Salesforce.com.

Once again, we inject the Account resource into the controller and fetch the Account from Salesforce.com with “/accounts/:id.json” via Account.get(). We also set the $scope variable mode to ‘display’ so that the page initially displays the details of the Account instead of the edit form. The update function at the bottom PUTS our data to “/accounts/:id.json” via Account.update() to update the Account in Salesforce.com.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'use strict';
 
var app = angular.module('app');
 
app.controller('AccountDetailCtrl', function($scope, $routeParams, Account) {
 
  $scope.account = Account.get({id:$routeParams.id});
  $scope.mode = 'display';
 
  $scope.edit = function() {
    $scope.mode = 'edit'; 
  }
 
  $scope.cancel = function() {
    $scope.mode = 'display'; 
  }  
 
  $scope.update = function() {
    $scope.mode = 'display'; 
    Account.update({id:$routeParams.id}, $scope.account, function() {
      // performs some operation when the callback completes like error checking
      console.log('Callback completed!');
    });
 
  }    
 
});

The details.html template has two sections; one for displaying the Account and a form for updating the account. These sections display based upon the value of ‘mode’ in the ng-show directive. The update form uses the ng-model directive to display the values of the model attributes. The two-way binding updates the model immediately. For example, each change you make to the Account name in the text field will immediately update the Account name at the top of the page as they are both bound to the same model.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<a class="btn" href="/#" style="margin-top:15px;margin-bottom:15px"><i class="icon-home"></i> Back</a>
 
<div ng-controller="AccountDetailCtrl">
 
<h1>{{account.Name}}</h1>
 
<span ng-show="mode == 'display'">
 
  <table class="table" style="width:50%">
    <tbody>
    <tr>
      <td width="20%">Type:</td>
      <td>{{account.Type}}</td>
    </tr>
    <tr>
      <td>State:</td>
      <td>{{account.BillingState}}</td>
    </tr>    
    <tr>
      <td></td>
      <td></td>
    </tr>      
    </tbody>
  </table>
 
  <button type="button" class="btn btn-primary" ng-click="edit(account)">Edit Account</button>
</span>
 
<span ng-show="mode == 'edit'">
 
  <form  name="editForm" ng-submit="update()">
    <fieldset>
    <legend>Edit Account</legend>
 
    <label>Account name</label>
    <input type="text" ng-model="account.Name" required><br/>
 
    <label>Type</label>
    <input type="text" ng-model="account.Type" required><br/>
 
    <button type="submit" class="btn btn-primary">Submit</button> 
    <button type="button" class="btn"  ng-click="cancel()">Cancel</button>
 
    </fieldset>
  </form>
 
</span>
 
</div>

So there you have a nice little AngularJS application that you can reference for your next project! Enjoy!

VN:F [1.9.15_1155]
Rating: 10.0/10 (3 votes cast)
VN:F [1.9.15_1155]
Rating: +2 (from 2 votes)

Categories: AngularJS

No Comments

Appirio Tough Mudder – “RIP Clint Ruiz”

May 10th, 2013

My Son, SGT DouglasOn May 19th some of us from Appirio are doing Tough Mudder in Jacksonville as part of “Team Ruiz” to raise money for a couple of reasons. I’ve given a lot to the Salesforce developer community so I’m hoping in turn I can persuade some people step up and pay it forward after hearing this story.

So that’s my son on the left. He’s an arabic-speaking Army Special Operations sergeant heading back for his second deployment to Afghanistan in the next couple of days (literally). The tattoo on his chest is for his good friend, 22 year old Sergeant Clint Ruiz, that was killed Afghanistan on October 25, 2012 in this blue on green incident. He’s survived by a wife and small son.

We are running the Tough Mudder to raise money for Wounded Warrior Project (hopefully my son will never need it) and also raise money for Clint’s Ruiz’s 2 year old son’s college fund. I’m hoping that you’ll donate some money to at least one (if not both) of the causes below.

Donate to Wounded Warrior Project
Donate to WWP on our “Team Ruiz” Tough Mudder page. I’ll let everyone know the total amount after the event.

Donate to College Fund
If you’d like to donate money to Clint Ruiz’s son’s college fund, please send it to my Paypal account (jeff@jeffdouglas.com) and I’ll see that it makes it to his parents. I’ll personally match each dollar that is donated.

THANKS!



VN:F [1.9.15_1155]
Rating: 10.0/10 (3 votes cast)
VN:F [1.9.15_1155]
Rating: +2 (from 2 votes)

Categories: Personal

No Comments

Why the Force.com @future Annotation Should Die!

April 4th, 2013

First of all I love asynchronously processing in Salesfoce. We use it all the time at CloudSpokes. I don’t actually mean that the @future annotation should die, per se, but I think there is a better approach. I see the annotation rising from the ashes like a phoenix!!! If you agree please take some time and vote for my idea below.

The @future annotation is typically used in one of two ways:

  1. Create a better user experience – Let’s say you have a process that whenever an Opportunity is created a number of calculations are made on a custom object. However, since these calculations don’t affect what the user is currently doing, why make them wait as these calculations are made? Apex methods marked with the @future annotation are executed asynchronously when Salesforce has available resources. A better solution is to create the Opportunity and call your calculations asynchronously so that the user does not have to wait for them to finish processing.

  2. Calls to external web services – As Force.com applications have taken more of centralized role in the enterprise application architecture, there is an evolving need to keep external systems in sync. Suppose you have a requirement (not uncommon) that each time you update a contact you have to call an external webservice to update the contact in SAP, Siebel, etc. Since callouts are prohibited in triggers, you need to call an Apex class with a @future method that is marked as (callout=true).

The @future annotation is a great tool but with great power comes great responsibility. Here are some things you need to keep in the back of your mind when using them:

  1. Depending on the number of licenses you have you may bump into some org-wide limits as Salesforce imposes a limit on the number of future method invocations. You can only have 200 method calls per full Salesforce user license or Force.com App Subscription user license, per 24 hours. This is understandable (i.e., limits != evil) but what if you are doing data loading/cleanup or have installed a managed package that puts you over your limit, you simply have to wait for you invocations to reset and somehow reprocess those items that failed.

  2. No more than 10 method calls per Apex invocation. This one is understandable as well but I’ve seen a number of projects where we’ve had to implement some other type of system (polling for instance) because the limitation makes this approach technically impossible. The example is, suppose you have a trigger that updates 11 contact records (or 200!) and needs to make a callout for each record. You are screwed unless you have the luxury of being able to rewrite your external webservice to accept a collection of records.

  3. You cannot call a method annotated with @future from a method that also has the @future annotation. We’ve run into this a number of times as the class hierarchy grows in larger projects. You want to reuse an existing class but what happens if it already calls a @future method? Or what happens if an managed package contains a @future method?

  4. The parameters for a @future method must be primitive data types, arrays of primitive data types, or collections of primitive data types. Not a big deal as you can typically pass the IDs of the affected records and query for them. But doesn’t that seem like a waste of resources if the Apex that calls the @future method already holds these records? It would be great if you could pass a collection of sObject or Apex objects.

  5. It’s difficult to orchestrate processes with @future annotations because these methods do not necessarily execute in the same order they are called.

  6. Unit tests are difficult to write. Period.

Here’s my alternative: Apex Queue

I know that you can “work around” most of these issues and believe me most developers do. But wouldn’t it be far less effort and more efficient to deprecate the @future annotation and replace it with an “Apex Queue”? Quese are not rocketsurgery and have been around for quite a long time. Let’s embrace them for Force.com development. “My kingdom for a queue!!” I say!

Now I’m neither an Engineer at Salesforce nor do I play one on TV but here’s what I think implementing a queue would involve. I’m sure there are technical implications that I am unaware of but I’ll give it a shot.

  1. Apex invocations are simply passed to the queue and processed sequentially when resources are available (i.e., it’s a queue). I typically don’t care when a process is kicked off but just that it did run and in a certain sequence. Would be great to have some sort of history similar to batch jobs.
  2. Higher limits for callouts would be awesome but there is a tipping point here. You can’t allow unlimited callouts but perhaps 200 callouts per invocation would be awesome to accomidate triggers.
  3. Ability to pass complex objects, sObjects and primitives as method parameters to methods in the queue.
  4. Bulk processing with ability to call Batch Apex. I would love to push a call to the queue that in turn kicks off a batch process in the same thread.
  5. No more issues with calling a @future method from a @future method as each call would be replaced by sending the Apex invocation to the queue.
  6. Much easier to test as you don’t have to worry about startTest() and stopTest().

So there you have it. My idea for Salesforce to implement an “Apex Queue”. If you like the idea, go vote it up.

VN:F [1.9.15_1155]
Rating: 9.9/10 (9 votes cast)
VN:F [1.9.15_1155]
Rating: +7 (from 7 votes)

Categories: Salesforce

2 Comments

Learn Google DevTools for Free at CodeSchool

March 22nd, 2013

It’s an understatement to say that I’m a fan of Code School. I love the way they’ve blended professional video screen casts, live coding in the browser, and gamification to make learning fun again. The music is a little campy sometimes but overall I’m addicted to it as you can see from my report card.

Yesterday they released a new course sponsored by Google to really dig into Chrome’s DevTools. I’ve always tinkered with DevTools but have never become a power user. I was always looking for some sort of tutorial to explain everything to me. Well here it is! The course involves beginning and advanced DOM and style manipulation, working with the console, debugging JavaScript, memory profiling and improving performance. The best part is that the course is free to everyone! No need to purchase a subscription… but I would if I were you.

VN:F [1.9.15_1155]
Rating: 10.0/10 (1 vote cast)
VN:F [1.9.15_1155]
Rating: +1 (from 1 vote)

Categories: Salesforce

No Comments

Setting Up Continuous Integration for Saleforce Development

March 18th, 2013

Continuous Integration (CI) for Force.com projects has been a popular topic lately. There are a number of blog post that describe the benefits and how you should go about doing it. However, after we discussed it on our #DifferentSpokes podcast last week, we received a number of emails asking for help on getting CI up and running. So I put together a short video on the process using Jenkins.

Here are the links that I reference in the video:

Force.com Migration Tool
Cloudbees
Sample Github repo for Jenkins
Salesforce + Git + Eclipse + EGIT = Better and Distributed Source Control
How To Use Git, GitHub and the Force.com IDE

VN:F [1.9.15_1155]
Rating: 10.0/10 (1 vote cast)
VN:F [1.9.15_1155]
Rating: 0 (from 0 votes)

Categories: Salesforce

2 Comments

CloudSpokes #DifferentSpokes with Josh Birk from Salesforce.com

February 22nd, 2013

Earlier this week we broadcast our third episode of #DifferentSpokes with a special guest, Josh Birk from Salesforce.com. If you missed it, it was a really entertaining episode with some interesting questions from Twitter. Obviously we focused on Salesforce.com related topics such as:

  • Some of the highlights of the Spring ’13 release and why the new Tooling API rules!
  • The growing tensions in the Salesforce Chicago office over differing opinions on breakfast foods
  • Josh’s love affair with anything related to JavaScript
  • His recent CI work with Jenkins for Salesforce.com
  • Why JavaScript Remoting makes creating dynamic applications in Force.com fun again
  • How to make Backbone.js and Visualforce play nicely
  • His preferences on Java Script debuggers, IDEs, modern text editors, old school text editors, distribution of linux and JavaScript templating frameworks.

Our next episode will be focusing on Angular.js so don’t miss that!

VN:F [1.9.15_1155]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.15_1155]
Rating: +1 (from 1 vote)

Categories: CloudSpokes, Salesforce

1 Comment

CloudSpokes – Heroku Success Story

January 24th, 2013

So my customer success for CloudSpokes on Heroku went live today with a link in their developer newsletter.

Pretty good stuff on how the CloudSpokes community members built the CloudSpokes site on Database.com and Heroku. We honestly don’t think it would have been possible to do with any other platforms in such a short amount of time.

VN:F [1.9.15_1155]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.15_1155]
Rating: 0 (from 0 votes)

Categories: Heroku

No Comments

Schedule Apex Exception – “No Apex Classes Found”?

January 17th, 2013

So I ran across this issue a couple of months ago and forgot to blog about it for my reference and anyone else that runs across this problem. So here’s the issue, I have an Apex class scheduled in production that runs another Apex class. I’ve made some changes to this second class and need to deploy it to production. Before you do that, for Force.com platform requires you to delete the scheduled job for that class since they are related.

No problem. So I deleted the scheduled class, pushed my new code to production (passes all tests! w00t!) and went back to schedule this class to run and saw this error:

I went and looked at the class and noticed that it was no longer valid:

So here’s how you fix the issue so that the class can be scheduled. You have to simply have to make salesforce recompile the classes and then it will be available to schedule.

VN:F [1.9.15_1155]
Rating: 6.0/10 (2 votes cast)
VN:F [1.9.15_1155]
Rating: +2 (from 2 votes)

Categories: Salesforce

No Comments

Force.com Streaming API with Ruby

January 16th, 2013

I must publicly confess my love with the Force.com Streaming API. (Don’t tell my wife.) Last September I wrote a blog post entitled, Node.js Demo with Force.com Streaming API & Socket.io that showed how to stream events from Saleforce.com to the browser using Node.js. It was a pretty cool app if you are familiar with Node.js.

Then at Dreamforce ’12 I did an Un-Conference session called, “Log Force.com Events in REALTIME with Papertrail” which was a knock-off but showed how to create an external logger for Salesforce using the Force.com Streaming API. Pretty slick stuff but again in Node.js.

Well I’ve found a much easier way to use the Force.com Streaming API than my previous attempts thanks to the Restforce ruby gem. According to the docs “… the Restforce gem makes implementing pub/sub with Salesforce a trivial task”. A bold statement but entirely true.

So I put together a sample rails app that you can use as a starter with the Force.com Streaming API. Just fork this repo, watch the video below and then follow the simple, step-by-step instructions on the repo to get started. The demo app streaming events from a “Log__c” custom object to the rails app with in turn uses Papertrail as a logger.

Here’s the file that does the heavy lifting for you. It connects to your org with the Restforce client, starts listening for events on the “LogEntries” channel and then once it receives it, outputs it to Papertrail through “puts”.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
require 'restforce'
require 'faye'
 
# Initialize a client with your username/password.
client = Restforce.new :username => ENV['SFDC_USERNAME'],
:password => ENV['SFDC_PASSWORD'],
:security_token => ENV['SFDC_SECURITY_TOKEN'],
:client_id => ENV['SFDC_CLIENT_ID'],
:client_secret => ENV['SFDC_CLIENT_SECRET']
 
# simply for debugging
puts client.to_yaml
 
begin
 
client.authenticate!
puts 'Successfully authenticated to salesforce.com'
 
EM.next_tick do
client.subscribe 'LogEntries' do |message|
puts "[#{message['sobject']['Level__c']}] #{message['sobject']['Class__c']} - #{message['sobject']['Short_Message__c']} (#{message['sobject']['Name']})"
end
end
 
rescue
puts "Could not authenticate. Not listening for streaming events."
end
view raw streaming.rb This Gist brought to you by GitHub.
VN:F [1.9.15_1155]
Rating: 10.0/10 (2 votes cast)
VN:F [1.9.15_1155]
Rating: +1 (from 1 vote)

Categories: Heroku, Ruby, Salesforce

No Comments

Restforce Ruby Gem for Salesforce.com

January 8th, 2013

As one of the committers for the Databasedotcom gem, I follow most of the other committers to see what they are working on. I was pleasantly surprised a few months back when Eric Holmes started pushing code for a project called “Restforce“. I nearly fell out of my seat when I read that it was billed as a “lighter weight alternative to the databasedotcom gem”.

We’ll, we been using it for a couple of months now to build our new CloudSpokes API, and I have to say that it’s a pretty impressive gem. Eric has been consistently refactoring and adding features and it extremely responsive. I’ve submitted a few issues and he’s gotten back to me immediately. Check out the repo for complete details but here’s a high level overview of the features:

  • A clean and modular architecture using Faraday middleware and Hashie::Mash’d responses. Add your own middleware to Restforce!
  • Multiple OAuth flows.
  • Support for interacting with multiple users from different orgs.
  • Support for parent-to-child relationships.
  • Support for aggregate queries.
  • Optional bang CRUD methods (create, update, upsert, destroy) that raise salesforce.com exceptions
  • Support for the Streaming API with EventMachine
  • Support for blob data types (uploading files)
  • Support for GZIP compression.
  • Support for custom Apex REST endpoints. Winning!!
  • Support for decoding Force.com Canvas signed requests.

He’s written a number of sample applications in rails and sinatra so if you are writing ruby app that you would like to integrate with salesforce.com, I would highly recommend you check out Restforce.

VN:F [1.9.15_1155]
Rating: 10.0/10 (2 votes cast)
VN:F [1.9.15_1155]
Rating: +2 (from 2 votes)

Categories: Heroku, Ruby, Salesforce

No Comments

Feed

http://blog.jeffdouglas.com /

WordPress Appliance - Powered by TurnKey Linux