Appirio's Tech Blog

2011年6月24日金曜日

Ruby, Rails & Force.com REST API をHeroku上で使用する - デモアプリケーション

Rubyを学ぼうシリーズ(英語)」に続けて、Force.com REST APIを使ったサンプルアプリを完成させました。その際いくつかの問題に遭遇しましたが、幸いにも Quinton WallとHerokuのサポートに助けられました。(大文字小文字の区別がないApexとは違い) Heroku上では 'Account''account' は別物です。当たり前ですよね・・・。

さて、今回説明するのはHeroku上のRuby 1.9.2とRails 3.0.5で動作するRailsデモアプリケーションです。このアプリケーションは OmniAuth経由のOAuth2プロトコルを使って認証し、salesforce.comにアクセスします。またこのアプリケーションはForce.com REST APIを使い、レコードを取得、表示、新規レコードの作成と既存レコードの更新を行っています。これは私のような初心者が手始めに作るのにちょうど良いアプリケーションです。

私はまず Quinton Wallの(素晴らしい) omniauth-rails3-forcedotcomプロジェクトをforkしてこのプロジェクトを作り始めました。Force.com REST APIを利用する上で必ずやらなければいけないことの一つが、WEBrickがSSLで動作するようにすることです。OSX向けの良い説明をhereで見つけました。

アプリケーションを試してみる方はこちら

このアプリケーションのすべてのコードは github においてあります。自由にforkしてください。ビデオの後の説明のために、いくつかの重要な部分を抜粋しました。


app/controllers/accounts_controller.rb

accountコントローラーは認証をaccounts.rbに委譲し、Force.comと連携し、結果をまとめてビューに渡します。

require 'accounts'
 
class AccountsController < ApplicationController
  def index
  end
  
  def search
    @json = Accounts.search(params[:accountName])
  end
  
  def show
    @account = Accounts.retrieve(params[:id])
    @opportunities = Accounts.opportunities(params[:id])    
  end
  
  def create
     @account = Accounts.create
  end
  
  def edit
     @account = Accounts.retrieve(params[:id])
  end
  
  def save
    Accounts.save(params)
    redirect_to :action => :show, :id => params[:id]
  end  
  
  def new_opp 
    @account = Accounts.retrieve(params[:id])
  end
  
  def save_opp
    Accounts.create_opp(params)
    redirect_to :action => :show, :id => params[:id]
  end
 
end

lib/accounts.rb

Accounts.rb は、アプリケーションを動かすのに必要な力作業の大部分を担います。リクエストにヘッダ情報を正しく設定し、REST API を使って、実際に Force.com に対して呼出しを行っています。

require 'rubygems'
require 'httparty'
 
class Accounts
  include HTTParty
  #doesn't seem to pick up env variable correctly if I set it here
  #headers 'Authorization' => "OAuth #{ENV['sfdc_token']}"
  format :json
  # debug_output $stderr
 
  def self.set_headers
    headers 'Authorization' => "OAuth #{ENV['sfdc_token']}"
  end
 
  def self.root_url
    @root_url = ENV['sfdc_instance_url']+"/services/data/v"+ENV['sfdc_api_version']
  end
  
  def self.search(keyword)
    Accounts.set_headers
    soql = "SELECT Id, Name, BillingCity, BillingState, Phone from Account Where Name = \'#{keyword}\'"
    get(Accounts.root_url+"/query/?q=#{CGI::escape(soql)}")
  end
  
  def self.create()
    Accounts.set_headers
    headers 'Content-Type' => "application/json"
    
    options = {
      :body => {
          :Name => "1234"
      }.to_json
    }
    response = post(Accounts.root_url+"/sobjects/Account/", options)
    # puts response.body, response.code, response.message
  end
  
  def self.save(params)
    Accounts.set_headers
    headers 'Content-Type' => "application/json"
    
    options = {
      :body => {
          :billingcity => params[:BillingCity]
      }.to_json
    }
    p options
    response = post(Accounts.root_url+"/sobjects/Account/#{params[:id]}?_HttpMethod=PATCH", options)
    # 201 response.body equals success
    # puts response.body, response.code, response.message
  end
  
  def self.retrieve(id)
    Accounts.set_headers
    get(Accounts.root_url+"/sobjects/Account/#{id}?fields=Id,Name,BillingCity,BillingState,Phone,Website") 
  end
  
  def self.opportunities(accountId)
    Accounts.set_headers
    soql = "SELECT Id, Name, Amount, StageName, Probability, CloseDate from Opportunity where AccountId = \'#{accountId}\'"
    get(Accounts.root_url+"/query/?q=#{CGI::escape(soql)}")
  end
  
  def self.create_opp(params)
    Accounts.set_headers
    headers 'Content-Type' => "application/json"
    
    options = {
      :body => {
          :name => params[:name],
          :amount => params[:amount],
          :accountId => params[:id],
          :amount => params[:amount],
          :closeDate => params[:closeDate],
          :stageName => params[:stageName]
      }.to_json
    }
    response = post(Accounts.root_url+"/sobjects/Opportunity/", options)
    # 201 response.body equals success
    # puts response.body, response.code, response.message
  end
 
end

Posted by Jeff Douglas (Appirio US)
[原文へ(英語)]

0 コメント:

コメントを投稿

 
2006-2011 Appirio Inc. All rights reserved.
アピリオ | リソースセンター(英語) | お問い合わせ先 | 採用情報 | プライバシーポリシー(英語)