Updating a Record When Viewed using Std Page Layout

April 1st, 2014

forcetk-memeI recently had a scenario where I wanted to track the last time a Lead record was viewed in Salesforce for auditing purposes. I added a simple Last_Viewed__c date field to the Lead object and then set about updating it every time the record was displayed in the standard page layout.

I poked around the interwebs a bit to see if anyone had any success implementing this but no luck. There was a lot of talk about overriding the entire standard page layout with a new Visualforce page but I really didn’t want to go that route. So I think I came up with a solution that is pretty simple to implement. In a nutshell, you create an inline Visualforce page that uses Pat Patterson’s super-awesome ForceTK JavaScript library to update the record on page load using the REST API.

The first thing you need to do is download the forcetk.js libaray and jQuery. It has been tested on jQuery 1.4.4 and 1.5.2, but other versions may also work. I used 1.5.2. Next upload these two files as static resources with the names “forcetk” and “jquery152″.

Next, you need to add the correct REST endpoint hostname for your instance (i.e. https://na1.salesforce.com/ or similar) as a remote site in Your Name > Administration Setup > Security Controls > Remote Site Settings.

Now create a Visualforce page that has no display and only calls the REST API with forcetk. Make sure you use the standardController attribute so that you can embed it into your page layout. One thing to note on the code below. On line 12 when calling the update method, the last argument is a callback function. I’ve set this to null since I don’t really care about the outcome but you may want to display the response for debugging or some other purpose.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<apex:page standardController="Lead">
  <apex:includeScript value="{!$Resource.jquery152}"  />
  <apex:includeScript value="{!$Resource.forcetk}"  />
  <script type="text/javascript">
  // Get a reference to jQuery as forcetk needs it  
  $j = jQuery.noConflict();
  // create an instance of the REST API client
  var client = new forcetk.Client();
  // set the session ID to your current session ID
  client.setSessionToken('{!$Api.Session_ID}');
  // make you call to update the record!
  client.update("Lead", '{!Lead.Id}', 
    {Last_Viewed__c: new Date()}, null);  
  </script>
</apex:page>

The last step is to add this Visualforce page to your standard page layout. In the page layout editor, drag the Visualforce page to a section that is not collapsable (so it’s sure to be called), I added mine under the Created By field, and set the Visualforce Page Properties to 0px width and 0px height. This way it will not appear on the page to the user. Now, after the page finishes loading, the REST API will be called to update the Last_Viewed__c field with the current date! Viola!

VN:F [1.9.22_1171]
Rating: 10.0/10 (4 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Categories: Salesforce

3 Comments

Sample Ruby on Rails Force.com Canvas App

March 4th, 2014

Force.com Canvas apps are a great way to extend the Force.com platform with existing legacy apps or to take advantage of existing packages and libraries on other platforms. Lately I’ve been writing a lot of node.js apps but needed to whip up a quick demo using Rails and found it a little more difficult than I would have liked due to the restriction that Canvas apps need to run on https.

So I put together a sample Force.com Canvas application using rails 4, restforce and tunnels so you can run https from localhost.

You can find the code here.

Connected app setup

The first thing we need to do is create a new Connected App for our Canvas application. Log into your DE org and go to Setup -> Build -> Create -> Apps and click the New button at the bottom in the Connected Apps section.

Enter the Connected App Name (this is the display name for your app), API Name (this is how you'll reference your app) and your Contact Email.

Check the Enable OAuth Setting checkbox and enter your Callback URL as https://localhost and for the Selected OAuth Scopes, select Full access (full).

In the Canvas App Settings section, check the Force.com Canvas checkbox, enter https://localhost/canvas for Canvas App URL, set Access Method to Signed Request (POST) and select Chatter Tab for Locations.

Your resulting app should look something like:

canvas-app

Now we need to give your user access to this new app. Go to Setup -> Administrator -> Manage Apps -> Connected App and click the Edit link for your new app. Select Admin approved users are pre-authorized for Permitted Users and save the app.

The last step is to give your profile access to the app so that it will show up on the Chatter tab. Go to Setup -> Administer -> Manage Users -> Profiles and click the Edit link next to your profile (assumed it's SysAdmin). Now check the box next to your new app in the Connected App Access section and save the page.

Now if you click the Chatter tab, you should see your new app in the left sidebar.

Install the rails-canvas app

Now for the fun part. Let's clone the repo and setup the rails app.

# clone this repo
git clone git@github.com:jeffdonthemic/rails-canvas.git
cd rails-canvas
# install the required gems
bundle

Now we need to add our the Consumer Secret from our Connected app. Go back to your app and click on the Click to reveal link to display the secret. Now add this as your client secret for the app in terminal:

# add the app's secret to the environment
export CLIENT_SECRET=YOUR-SECRET

Start the application

Canvas apps need to run on https but this makes it difficult to develop and test on your local machine. However, with ruby you can use tunnels to proxy from https from http. In terminal, start your rails server:

rails s

Now open another tab in terminal and fire up tunnels:

sudo tunnels 443 3000

I had some issues using tunnels due to rvm, so I had to use:

rvmsudo tunnels 443 3000

After enter your password, you should see:

127.0.0.1:443 –(–)–> 127.0.0.1:3000

You'll want to visit https://localhost in your browser and accept any warning due to a perceived certificate error. This will block your Canvas app from running.

canvas-app1

Now you can go to the Chatter tab and access your application from the left sidebar. If everything works correctly, you should see a list of 10 contacts. There's also a page that displays your connection from Force.com.

VN:F [1.9.22_1171]
Rating: 8.0/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: +1 (from 1 vote)

Categories: Ruby, Salesforce

1 Comment

Announcing “Learn Force.com in 30 Days” Series

February 14th, 2014

learn-force-in-30-daysSince today is Valentine's Day I thought it would be an appropriate time to "spread the salesforce.com community love" with this announcement.

Last summer I started working on a new series called "Learn Force.com in 30 Days" intended for new developers and/or perhaps admins that want to start coding. The idea is that a person will subscribe to the series and each day (for 30 days… hence the title) they will receive a 10-15 minute video in their inbox on a specific Force.com topic. There will of course be slides, code, links for more info and funny pictures for your learning enjoyment. The series is intended to be high level but I will dig into some topics deeply like Apex, Visualforce and unit testing.

Disclaimer: this series is a total rip-off of Jeffrey Way's awesome Learn jQuery in 30 Days series.

I put the series on hold late last year for a couple of reasons. Our purchase of TopCoder took up a lot of bandwidth and I heard the pre-Dreamforce rumblings of Salesforce1 and wanted to make sure it was included (along with other Spring '14 goodies).

I'm in the process of finishing up the videos and then will start post-production editing, site development and documentation including a github repo with the code. I'm hoping to have this wrapped in the next couple of months. If anyone is interested previewing the content and providing me with feedback, please let me know. Would love the help!

So in no particular order, here are some of the topics I'm covering. Some may span multiple days or be covered in multiple parts of the series. I may even add or remove some topics depending on the content flow.

  • Force.com Platform
  • Tools
  • Security
  • Apex Language
  • SOQL & SOSL
  • Triggers
  • Apex Classes
  • Design Patterns
  • Controllers
  • Visualforce
  • Exceptions
  • DML
  • Testing
  • Deploying Code
  • Chatter in Apex
  • Batch Apex
  • Future Methods
  • Integration
  • Streaming API
  • Tooling API
  • SOAP API
  • REST API
  • Canvas Applications
  • Salesforce1
VN:F [1.9.22_1171]
Rating: 9.4/10 (30 votes cast)
VN:F [1.9.22_1171]
Rating: +26 (from 26 votes)

Categories: Salesforce

No Comments

Example Apps for nforce-tooling Plugin

January 29th, 2014

Yesterday I released the nforce-tooling plugin for nforce so today I thought I would follow up with some sample demos and a video walking through the process of using the plugin.

The video walks through two demos. The first is for standard functions like describe, querying tooling objects and creating/deleting records. The second demo show how to deploy a new Apex class to your org. You can find the code for these demos in the examples directory for the plugin.

To give you something to look at, here is the deploy.js code.

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
var nforce = require('nforce'),
  tooling = require('nforce-tooling')(nforce),
  Q = require("q");
 
var sfuser = process.env.SFUSER;
var sfpass = process.env.SFPASS;
 
// for the example, create a new class use the id here
var apexClassId = 'YOUR-APEX-CLASS-ID';
// the new code to update the class above with
var newApexCode = "public class ToolingDemo {\n String s = 's';\n}";
// we need this so we can clean up after ourselves
var metadataContainerId;
 
var org = nforce.createConnection({
  clientId: process.env.CLIENTID,
  clientSecret: process.env.CLIENTSECRET,
  redirectUri: 'http://localhost:3000/oauth/_callback',
  mode: 'single',
  plugins: ['tooling']
});
 
org.authenticate({ username: sfuser, password: sfpass}, function(err, resp){
  if(!err) {
    console.log('*** Starting Apex class deployment process... Hold tight. This is gonna be awesome. ***')
    createContainer('ExampleDeployContainer')
      .then(addUpdatedCode)
      .then(deploy)      
      .then(getDeployStatus)
      .fail(function(err) {
        console.log("== failure: " + err);
      });
  } else {
    console.log('Error connecting to Salesforce: ' + err.message);
  }
}); 
 
function createContainer(name) {
  var deferred = Q.defer();
  org.tooling.createContainer({name: name}, function(err, container) {
    // return the id of the newly created container
    if (!err) deferred.resolve(container.id);    
    if (err) deferred.reject(err);
  });         
  return deferred.promise;
}
 
function addUpdatedCode(containerId) {
  var deferred = Q.defer();
 
  // create the artifact that references the saved class and new code
  var artifact = org.tooling.createDeployArtifact('ApexClassMember', 
    {body: newApexCode, contentEntityId: apexClassId});
 
  org.tooling.addContainerArtifact({id: containerId, artifact: artifact}, function(err, resp) {
    // return the id of the container again
    if (!err) deferred.resolve(containerId)    
    if (err) deferred.reject(err);
  });         
  return deferred.promise;
}
 
function deploy(containerId) {
  var deferred = Q.defer();
  // so we can clean up
  metadataContainerId = containerId;
  org.tooling.deployContainer({id: containerId, isCheckOnly: false}, function(err, asnycContainer) {
    console.log('Deploying code...');
    // return the async container's id so we can check it's status
    if (!err) deferred.resolve(asnycContainer.id);
    if (err) deferred.reject(err);
  });
  return deferred.promise;
}
 
function getDeployStatus(asnycContainerId) {
  org.tooling.getContainerDeployStatus({id: asnycContainerId}, function(err, resp) {
 
    console.log('Checking status of the deployment...');
    if (resp.State === "Queued") {
      console.log("Status is currently queued. Checking deploy state again.");
      getDeployStatus(asnycContainerId);
    } else {
      if (resp.State === "Completed") {
        console.log("W00t! Code successfully deployed");
      } else if (resp.State === "Failed") {
        console.log("Deployment failed with: ");
        console.log(resp.CompilerErrors);
      } else if (resp.State === "Error") {
        console.log("Deployment failed with error: ");
        console.log(resp.ErrorMsg);
      } else {
        console.log("Deploy finished with a status of: " + resp.State);            
        console.log(resp);            
      }
 
      // delete the metadata container
      org.tooling.delete({type: 'MetadataContainer', id: metadataContainerId}, function(err, resp) {
        if (err) {
          console.log("Error deleting deployment container: " + metadataContainerId);
          console.log(err);
        }
      });           
 
    }
  });        
}
VN:F [1.9.22_1171]
Rating: 9.0/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Categories: Node.js, Salesforce

No Comments

Announcing Force.com Tooling API for Node.js (nforce)

January 28th, 2014

nforce-toolingOver Christmas break I stared playing around with the Force.com Tooling API in node.js. We have some ideas over at topcoder for the Tooling API and I wanted to build a POC to see how crazy I was.

After a couple of days I started to realize how cool the Tooling API could be and the development impact it could make. I’ve always been big fan and user of Kevin O’Hara‘s nforce package so I emailed him to see if he would be interested in including it in nforce. After a few emails we decided to go the Passport route and implement the new functionality with plugins that could be developed and maintained independently and not “muddy-up” the core nforce package. Brilliant! My guess is that there are more plugins coming down the road for nforce ;).

So while Kevin essentially rewrote nforce (added plugin functionality, improved performance, simpler signatures, etc), I worked on the nforce-tooling plugin. I did most of the work while on my vacation in Jamaica (you can only lay around in the sun drinking daiquiris for so long!) and finally release version 0.0.1 this morning.

Github repo: https://github.com/jeffdonthemic/nforce-tooling

Like anything else with Salesforce.com, it’s a work in progress as the Tooling API revs. I’ll be adding more features as they become available but please send me any issues or pull requests. I’ll be writing a few tutorials in the near future but for some sample code see the mocha tests. See the github readme for complete info.

The 0.0.1 plugin supports the following functionality:

createContainer() – Creates a container as a package for your workspace that manages working copies of Tooling objects, including collections of objects that should be deployed together.

getContainer() – Returns a container.

addContainerArtifact() – Adds an artifact to the container for deployment. The artifact object links the container, to the saved copy of the object (e.g., ApexClass), to the working copy of the object (e.g., ApexClassMember) for deployment.

deployContainer() – Compiles and deploys a container.

getContainerDeployStatus() – Returns the deploy status of a container.

deleteContainer() – Deletes a container.

getObjects() – Returns a collection of available Tooling API objects and their metadata.

getObject() – Returns the individual metadata for a specified object.

getRecord() – Returns high-level metadata for a specific object. For more detailed metadata, use getDescribe().

getDescribe() – Returns detailed metadata at all levels for a specified object.

getCustomField() – Returns the metadata on a custom field for a custom object. Includes access to the associated CustomField object in Salesforce Metadata API.

query() – Executes a query against a Tooling API object and returns data that matches the specified criteria.

insert() – Creates a new Tooling API object.

update() – Updates a Tooling API object with the specified data.

delete() – Deletes a Tooling API object.

executeAnonymous() – Executes some Apex code anonymously and returns the results.

getApexLog() – Returns a raw debug log.

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Categories: Node.js, Salesforce

No Comments

Roll Your Own Node CLI for Force.com

January 14th, 2014

I’d like to start off this post with two admissions: 1) I love the Force.com CLI 2) I don’t know Go. Fact #2 makes it hard for me to extend the CLI for my own (selfish) purposes. However, I am fairly handy with JavaScript and Node.js so that’s where I mostly work.

I’ve been using a node CLI for the past couple of months when prototyping new features with different Force.com APIs. It’s been extremely useful when prototype/testing with the new Tooling API (here’s the gist of the module I’ve been working on if you want to add the code). What’s makes it so useful is that you just add your connected apps settings, authenticate using nforce (FTW!) and then go ahead making REST calls to Force.com. Super easy!

force-cli-node

I thought other might get some use out of it so I ripped out all of my crap code and pushed it to github. There are a couple of sample commands to get you started but feel free to make enhancements. It’s also Promise-based which should make life easier when dealing with Force.com APIs.

To get started from terminal, clone this repo and run npm install to install the dependencies. You may also have to run chmod 777 ./bin/cli to make the file executable on OS X.

You’ll then need to enter your connection parameters into config.js for Force.com. To test you connection, simply run bin/cli login which should return a connection object.

To see the available commands run bin/cli –help.

As of right now, each command initially authenticates to Force.com before running. You may want to cache the connection in redis to speed things up. I did not want to add this dependency which would have made it harder to get started.

The code for the CLI is rather small and should be easy to grok. The CLI “executable” uses commander, is self documenting and simply delegates calls to /lib/force.js.

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
#!/usr/bin/env node
 
var program = require('commander'),
  force = require("../lib/force.js");
 
program
  .version('0.0.1')
 
program
  .command('login')
  .description('Logs into salesforce and returns an access token')
  .action(function(){
    force.login();
});
 
program
  .command('query [sobject]')
  .description('Queries for 5 records from the specified sObject.')
  .action(function(sobject){
    force.query(sobject);
});
 
program
  .command('fetch [sobject] [id]')
  .description('Fetches a specific record by id.')
  .action(function(sobject, id){
    force.fetch(sobject, id);
});  
 
program
  .command('create [sobject] [name]')
  .description('Inserts a new record with a name only.')
  .action(function(sobject, name){
    force.insert(sobject, name);
});    
 
program
  .command('update [sobject] [id] [value]')
  .description('Updates a specific record with value as its name.')
  .action(function(sobject, id, value){
    force.update(sobject, id, value);
});  
 
program.parse(process.argv);

The real guts of the CLI is the force.js module which uses nforce to talk to Force.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
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
var  nforce = require("nforce"),
  Q = require("q"),
  request = require('request'),
  config = require("../config.js").config;
 
var org = nforce.createConnection({
    clientId: config.sfdc.client_id,
    clientSecret: config.sfdc.client_secret,
    redirectUri: 'http://localhost:3000/oauth/_callback',  
    environment: config.sfdc.environment,
    mode: 'multi' 
  });   
 
// authenticate to force.com and returns connection object
function login() {
  var deferred = Q.defer();
  org.authenticate({ username: config.sfdc.username, password: config.sfdc.password}, function(err, resp){
    if(!err) {
      console.log('Access Token: ' + resp.access_token);
      deferred.resolve(resp);
    } else {
      console.log('Error connecting to Salesforce: ' + err.message);
      deferred.reject(err);
    }
  });      
  return deferred.promise;
} 
 
// qeuries for 5 records by the specified sObject
function query(sobject) {
 
  login()
    .then(function(connection) {
 
      var q = 'select id, name from '+sobject+' limit 5';
      org.query(q, connection, function(err, resp){
        if(!err) {
          resp.records.forEach(function(item) {
            console.log(item.getId() + " -- " + item.Name);  
          });            
        } 
        if (err) console.log("ERROR: " + err.message); 
      });             
 
    });
 
}
 
// returns a specific record
function fetch(sobject, id) {
 
  login()
    .then(function(connection) {
 
      var record = nforce.createSObject(sobject, {id: id});
 
      org.getRecord(record, connection, function(err, resp){
        if(!err) console.log(resp.getId() + " -- " + resp.Name);  
        if (err) console.log("ERROR: " + err.message); 
      });             
 
    });
 
}
 
// inserts a new record for specified sObject (name field only)
function insert(sobject, name) {
 
  login()
    .then(function(connection) {
 
      var record = nforce.createSObject(sobject);
      record.name = name;
 
      org.insert(record, connection, function(err, resp){
        if(!err) console.log(resp);  
        if (err) console.log("ERROR: " + err.message); 
      });             
 
    });
 
}
 
// updates a specific record with a new name value
function update(sobject, id, newName) {
 
  login()
    .then(function(connection) {
 
      var record = nforce.createSObject(sobject, {id: id, name: newName});
 
      org.update(record, connection, function(err, resp){
        if(!err) console.log("Record updated.");  
        if (err) console.log("ERROR: " + err.message); 
      });             
 
    });
 
}
 
exports.login = login;
exports.query = query;
exports.fetch = fetch;
exports.insert = insert;
exports.update = update;

Hope you enjoy it and it makes your life easier.

VN:F [1.9.22_1171]
Rating: 9.0/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Categories: Node.js, Salesforce

No Comments

Fun with Force.com CLI, JSON and .jq

December 12th, 2013

We are terminal junkies at CloudSpokes so we were really excited when the Force.com CLI was announced. One of our favorite command line tools is .jq, a lightweight and flexible command-line JSON processor. My buddy and terminal Yoda, Kyle Bowerman, turned me on to this utility. jq is like sed for JSON data – you can use it to slice and filter and map and transform structured data with the same ease as sed, awk, grep.

So how does this work with Salesforce you ask? You can make virtually any call that returns JSON (let’s say a REST API query), search through the JSON, pipe the results into a shell script and then run that with the Force.com CLI.

The first thing you need to do is install .jq. Not terribly hard as they have binaries for most systems. Then you’ll need to get a session token for the REST API call. You’ll need to pass this session Id in the header with each REST call. Log into the Workbench for your org and go to Info -> Session Information. You’ll see your session Id under the Connection folder.

So the simplest use case is to query for 3 accounts and run them through .jq to see what we get:

curl https://na5.salesforce.com/services/data/v29.0/query?q=select+name,+id+from+account+order+by+id+limit+3 -H 'Authorization: Bearer [YOUR-SESSION-ID]' | jq '.'

jq1

So let’s say now that you want to get just the Names for all of these records. These are stored in the ‘records’ property so we are gonna tell .jq to iterate over the records array and just output the Name property:

curl https://na5.salesforce.com/services/data/v29.0/query?q=select+name,+id+from+account+order+by+id+limit+3 -H 'Authorization: Bearer [YOUR-SESSION-ID]' | jq '.records[].Name'

jq2

Now here’s where the fun stuff begins. Let’s use .jq to create a shell script to run with the Force.com CLI to update some records:

curl https://na5.salesforce.com/services/data/v29.0/query?q=select+name,+id+from+account+order+by+id+limit+3 -H 'Authorization: Bearer [YOUR-SESSION-ID]' | jq '"force record update Account \(.records[].Id) State:NY"'

jq3

You can easily send the contents generated by .jq to a shell script that you can execute against your org by appending ‘> my_script.sh’:

curl https://na5.salesforce.com/services/data/v29.0/query?q=select+name,+id+from+account+order+by+id+limit+3 -H 'Authorization: Bearer [YOUR-SESSION-ID]' | jq '"force record update Account \(.records[].Id) State:NY"' > my_script.sh

There are a ton of things you can do with .jq so make sure you check out the manual. Happy scripting! Enjoy!

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

Categories: Salesforce

No Comments

What does Heroku1 mean for Developers?

December 6th, 2013

heroku1 Heroku1 was announced a couple of weeks ago at Dreamforce but was overshadowed by the Salesforce1 fanfare. Salesforce1 is awesome but, I think Heroku1 is just as important, if not more, as it will open the platform up to new developers and new ways to develop apps for Force.com.

Let me start out by saying we love Heroku at CloudSpokes and Appirio. We were the first platinum partner, built our entire CloudSpokes platform on it (Heroku case study) and are currently hosting over 160+ apps on it. A majority of the applications built for CloudSpokes challenges are done on Heroku not be cause we mandate it but because developers absolutely love the ease, power and flexibility of the platform. So to say the least, we were excited when they announced Heroku1.

Heroku announced Force.com client libraries for Ruby and Node.js, force.rb and force.js respectively. There’s an interesting backstory to these two libraries as they were both started by the community. The Ruby restforce gem was forked and became force.rb and the Node.js nforce package was forked and became force.js.

When Salesforce purchased Heroku a couple of years ago they engaged PivotalLabs (now Pivotal) to build the databasedtocom Ruby gem as part of their community outreach. The gem had some serious limitations so, being community driven, people submitted issues and pull requests. Shortly after the gem’s release, PivotalLabs was purchased by EMC and the main developer, Danny Burkes, went MIA. Ruby developers were becoming quite irritated and this didn’t look good for Heroku (it’s part of their repo!) as it looked like they were ignoring the library. No issues were getting fixed and pull requests were hanging in limbo. We ran some challenges at CloudSpokes to fix issues but realized that the problems were too numerous. About a year later, one of the committers, Eric Holmes, started working on a new restforce gem as “…a lighter weight alternative to the databasedotcom gem that offers greater flexibility and more advanced functionality.” We quickly switched to the new restforce gem and use it in many production applications. Eric is very responsive and has added some great functionality. We are extremely happy with it.

Force.js is a much easier story as it was born out of Kevin O’Hara’s love of Salesforce and everything JavaScript. I’ve committed a little to the library (a tiny bit) and we have a number of production applications running with it at CloudSpokes and Appirio. Saying that we are very happy with the library is an understatement. This is our go-to library.

What makes the announcement of these libraries so important is that Jesper Jorgensen stood on the stage during the Developer Keynote and stated that Salesforce would officially support these libraries. This should give the developer community the confidence that, unlike the databasedotcom gem, Heroku will put some development resources into the libraries. I do have a couple of concerns as they haven’t stated how they will support these libraries and if the will only be supporting their forks. Will their changes also be submitted to the upstream nforce and restforce libraries or will they develop their forks independently? The latter would severely tarnish the community spirit in which these libraries were developed and all the hard work that’s been done so far.

Heroku also released a command line tool called the Force.com CLI for those of us that prefer the command prompt to a browser. I actually got a sneak peek at this a couple of months ago from Quinton Wall and if you are a subscriber to my Force.com Weekly newsletter, you would have seen a sneak peak back in November.

force-cli-tweet

Wade Wegner has an awesome overview but the scripting possibilities are virtually endless. Imagine being able to cURL a REST URL for an Account record, use jq to interrogate the returned JSON and then create an Opportunity for that Account. All without opening a browser! Brilliant!

So I left the cornerstone of Heroku1 for last: Heroku Connect. First of all, what is Heroku Connect? In a nutshell, it is a service that syncs data from Salesforce into Heroku Postgres (or MySQL on Amazon) automatically, handling many of the common issues of using an API such as local caching and conflict resolution. Why is this so important? Since many of the development languages that run on Heroku are heavily optimized for SQL databases, working with the Salesforce APIs can be somewhat of a challenge even when using restforce and nforce. Using Heroku Connect, developers can used their familiar workflows. Their reads and writes are straight to the database using Mongoose or ActiveRecord, they can write mocha and rspec tests using the same patterns they are used to and leverage all the #awesomesause of Postgres (fork, follow, share). These changes are propagated to Salesforce in the background and the developer really doesn’t need to know much about the details.

The CloudSpokes team got a demo of Heroku Connect (originally Cloudconnect) at Dreamforce 2012 by Adam Gross and started piloting the service last summer. We’ve been using it in production for nearly 6 months now are are really happy with it. It makes building an API with Force.com on Heroku sooo much easier. Since the entire Cloudconnect team is moving to Heroku, we are excited to see how the service evolves. I’m sure they have a lot of backlog ideas, but a couple of things I would like to see is perhaps the use of the Force.com Streaming API and some object level security implementations. Currently the service polls Salesforce for changes to records. Not sure if it’s possible, but it may be nice to speed up this process by using PushTopics to notify the services of new or modified records. Also, an issue we faced was due to the sharing model we always read from Salesforce for objects that have a private sharing model to determine if a user has access. It would be nice to bake this into the services somehow. My $.02.

I think Heroku1 is off to a good start with these new features but I’d still love to see some tighter integration between Heroku and Force.com.

VN:F [1.9.22_1171]
Rating: 9.7/10 (7 votes cast)
VN:F [1.9.22_1171]
Rating: +2 (from 2 votes)

Categories: Heroku, Salesforce

No Comments

What does Salesforce1 mean for Developers?

November 26th, 2013

For the past few years, the salesforce.com mantra has been “Chatter”. Everything was Chatter and everything connected to Chatter. Chatter was the way, the truth and the life. If you’ve been watching salesforce.com recently you may have noticed a lot of talk about mobile; especially with the release of the mobile packs for development. Last week at Dreamforce, salesforce.com announced Salesforce1 with much hype and fanfare. It was billed as “One Customer Platform to Connect‎” but what does this mean for the average Force.com developer? How will this impact our daily lives?

From a high level Salesforce1 is a unifying, mobile-ready, API-enabled wrapper (10x more APIs for your development pleasure!!) around everything Salesforce.com offers. They have stated that every new feature must be designed for mobile first (responsive design, features based upon device) and have an API for developers. There’s a big push to open up the existing platform by releasing new and improved APIs. Hurrah!

The marketing message for “Salesforce1” is still a little fuzzy to me. Salesforce1 is both a mobile application and platform on which to build mobile applications. Looking at the docs and running through some tutorials, it seems to provide the best of both worlds. Administrators can build declaratively (who needs developers?) while coders can can leverage their favorite development language to create rich, interactive applications for Salesforce1.

Declaratively creating apps is almost too simple. Even I can do it. Create mobile page layouts for interacting with your records or create a publisher action to implement custom functionality (e.g., send Christmas card) using custom actions with Visualforce or Canvas apps and easily expose it in Salesforce1.

If code is more your thing then there’s plenty to love no matter what your language of choice is. If you know Visualforce and Apex, you can easily extend the Salesforce1 app and give your mobile users the functionality they need. There’s also a pilot for Force.com Canvas so you can use virtually any language to integrate Salesforce1 with third-party web applications. If you love RESTful endpoints, and who doesn’t, custom actions are automatically REST-enabled! #FTW!

Salesforce1 also includes “flexible pages” which is a type of custom layout. These pages sit somewhere between page layouts and Visualforce pages and allow you to create a home page for third-party apps that you can add directly to Salesforce1 mobile navigation.

If native app dev tricks your trigger, the Salesforce Mobile SDK provides for iOS and Android development. You can also use it to implement a native container for HTML5 and hybrid apps.

There’s a lot of work to do to connect all of the people, things and devices in the world so head on over to the new developer.force.com and get started today!

VN:F [1.9.22_1171]
Rating: 9.3/10 (11 votes cast)
VN:F [1.9.22_1171]
Rating: +5 (from 5 votes)

Categories: Salesforce

2 Comments

DF13 Session Recap – Build your API with Force.com and Heroku

November 22nd, 2013

My talk at Dreamforce 13, “Build your API with Force.com and Heroku” went off pretty well. Thanks for everyone that came out! As you can see from the picture, it was “sitting” room only. The Developer Theatre was a awesome place to present. I really loved the vibe and energy as people walked in and out.

I only had 30 minutes for my session, but despite someone needing medical attention during my wrap-up, I still finished with a minute to spare. After the paramedics came the guy appeared to be alright. I’m hoping he was simply over stimulated from my presentation and not simply bored to near death.

You can find the source code that I used for my demo app at this repo. Feel free to pick it apart and send me any questions you might have. The slides are on Slideshare for your viewing pleasure. I heard that the theatre sessions were going to be recorded this time but I’m not sure of that.

VN:F [1.9.22_1171]
Rating: 10.0/10 (4 votes cast)
VN:F [1.9.22_1171]
Rating: +2 (from 2 votes)

Categories: Appirio, Salesforce

3 Comments

Feed

http://blog.jeffdouglas.com /