class Salesforce::Rest::AsfRest
This is the mother class of all Salesforce
REST objects all subclasses need to set the collection name. In ActiveResource
convention, pluralized elements has the ending ‘s’; whereas, in Force.com REST, that ‘s’ is not there. e.g. set_collection_name “User”
TODO cannot do “SObject.find(:all)” due to a defect in the ActiveResource
framework, see -> ActiveResource::Base line # 885
def instantiate_collection(collection, prefix_options = {}) collection.collect! { |record| instantiate_record(record, prefix_options) } end
As Ruby Hash has not collect! method, only Array, We we get back from Salesforce
is a hash <sobject><objectDescribe><.….></objectDescribe><recentItems>…</recentItems></sobject>
Public Class Methods
removing .…../UID.json
# File lib/Salesforce/rest/asf_rest.rb, line 291 def collection_path(prefix_options = {}, query_options = nil) prefix_options, query_options = split_options(prefix_options) if query_options.nil? "#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}" end
Again the delete feature from ActiveResource
does not work out of the box. Using custom delete function
# File lib/Salesforce/rest/asf_rest.rb, line 141 def self.delete(id, header=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@auth_header"), rest_svr=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@rest_svr"), api_version=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@api_version")) class_name = self.name.gsub(/\S+::/mi, "") path = "/services/data/#{api_version}/sobjects/#{class_name}/#{id}" target = rest_svr + path resp = Salesforce::Rest::AsfRest::call_rest_svr("DELETE", target, header) # HTTP code 204 means it was successfully deleted. if resp.code != 204 message = ActiveSupport::JSON.decode(resp.body)[0]["message"] Salesforce::Rest::ErrorManager.raise_error("HTTP code " + resp.code.to_s + ": " + message, resp.code) else return resp end end
removing .…../UID.xml
# File lib/Salesforce/rest/asf_rest.rb, line 286 def element_path(id, prefix_options = {}, query_options = nil) prefix_options, query_options = split_options(prefix_options) if query_options.nil? "#{prefix(prefix_options)}#{collection_name}/#{id}#{query_string(query_options)}" end
Again the find feature from ActiveResource
does not support multi-user access Using custom Find function
# File lib/Salesforce/rest/asf_rest.rb, line 160 def self.find(id, header=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@auth_header"), rest_svr=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@rest_svr"), api_version=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@api_version")) class_name = self.name.gsub(/\S+::/mi, "") path = "/services/data/#{api_version}/sobjects/#{class_name}/#{id}" target = rest_svr + path resp = Salesforce::Rest::AsfRest::call_rest_svr("GET", target, header) # HTTP code 204 means it was successfully deleted. if resp.code != 200 message = ActiveSupport::JSON.decode(resp.body)[0]["message"] Salesforce::Rest::ErrorManager.raise_error("HTTP code " + resp.code.to_s + ": " + message, resp.code) else return resp end end
Run SOQL, automatically CGI::escape the query for you.
# File lib/Salesforce/rest/asf_rest.rb, line 215 def self.run_soql(query, header=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@auth_header"), rest_svr=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@rest_svr"), api_version=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@api_version")) class_name = self.name.gsub(/\S+::/mi, "") safe_query = CGI::escape(query) path = "/services/data/#{api_version}/query?q=#{safe_query}" target = rest_svr+path resp = Salesforce::Rest::AsfRest::call_rest_svr("GET", target, header) #resp = get(path, options) if (resp.code != 200) || !resp.success? message = ActiveSupport::JSON.decode(resp.body)[0]["message"] Salesforce::Rest::ErrorManager.raise_error("HTTP code " + resp.code.to_s + ": " + message, resp.code) end return resp end
Run SOQL, automatically CGI::escape the query for you. This is with given credentials -> query, security_token, rest_svr, version the path with appropriate api_version, CGI escaping the query string is included in this method.
# File lib/Salesforce/rest/asf_rest.rb, line 235 def self.run_soql_with_credential(query, security_token, rest_svr, api_version) header = { "Authorization" => "OAuth " + security_token, "content-Type" => 'application/json' } #set the path with appropriate api_version, include CGI escaping the query string safe_query = CGI::escape(query) path = "/services/data/#{api_version}/query?q=#{safe_query}" target = rest_svr + path #get the result resp = Salesforce::Rest::AsfRest::call_rest_svr("GET", target, header) if (resp.code != 200) || !resp.success? message = ActiveSupport::JSON.decode(resp.body)[0]["message"] Salesforce::Rest::ErrorManager.raise_error("HTTP code " + resp.code.to_s + ": " + message, resp.code) end return resp end
Run SOSL, do not use CGI::escape -> SF will complain about missing {braces}
# File lib/Salesforce/rest/asf_rest.rb, line 252 def self.run_sosl(search, header=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@auth_header"), rest_svr=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@rest_svr"), api_version=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@api_version")) options = { :query => {:q => search}} class_name = self.name.gsub(/\S+::/mi, "") path = URI.escape("/services/data/#{api_version}/search/?q=#{search}") target = rest_svr + path resp = Salesforce::Rest::AsfRest::call_rest_svr("GET", target, header) if (resp.code != 200) || !resp.success? message = ActiveSupport::JSON.decode(resp.body)[0]["message"] Salesforce::Rest::ErrorManager.raise_error("HTTP code " + resp.code.to_s + ": " + message, resp.code) end return resp end
Run SOSL, do not use CGI::escape -> SF will complain about missing {braces} This is with given credentials -> Search_query, security_token, rest_svr, version
# File lib/Salesforce/rest/asf_rest.rb, line 269 def self.run_sosl_with_credential(search, security_token, rest_svr, api_version) header = { "Authorization" => "OAuth " + security_token, "content-Type" => 'application/json' } #set the path with appropriate api_version, with the search string path = URI.escape("/services/data/#{api_version}/search/?q=#{search}") target = rest_svr + path #get the result resp = Salesforce::Rest::AsfRest::call_rest_svr("GET", target, header) if (resp.code != 200) || !resp.success? message = ActiveSupport::JSON.decode(resp.body)[0]["message"] Salesforce::Rest::ErrorManager.raise_error("HTTP code " + resp.code.to_s + ": " + message, resp.code) end return resp end
set header for httparty
# File lib/Salesforce/rest/asf_rest.rb, line 53 def self.set_headers (auth_setting) headers (auth_setting) end
We are mocking OAuth type authentication. In our case, we use the SessionID obtained from the initial SOAP Web Services call - ‘login()’ OAuth2 is geared toward website to website authentication. In our case, we are the background data interchange between RoR app and Force.com database. Therefore, we use security id. example: connection.set_header(“Authorization”, ‘OAuth 00DA0000000XwIQ!AQIAQD_BX.pdxMz0YBKdkz45PijY0gMxH65JwvV6Yj4.hf44WJYqO9ug7DfhNbnxuO9buhbftiX9Qv5DyBLHauaJhqTh79vi’)
self.abstract_class = true
Setup the adapter
# File lib/Salesforce/rest/asf_rest.rb, line 84 def self.setup(oauth_token, rest_svr, api_version) @@oauth_token = oauth_token @@rest_svr = rest_svr @@api_version = api_version ? api_version : "v21.0" #take a dynamic api server version @@rest_svr_url = rest_svr + "/services/data/#{api_version}/sobjects" @@ssl_port = 443 # TODO, right SF use port 443 for all HTTPS traffic. #ActiveResource setting #self.site = "https://" + @@rest_svr_url self.site = @@rest_svr_url connection.set_header("Authorization", "OAuth " + @@oauth_token) # To be used by HTTParty @@auth_header = { "Authorization" => "OAuth " + @@oauth_token, "content-Type" => 'application/json' } # either application/xml or application/json base_uri rest_svr self.format = :json return self end
Update an object # TODO to use the call_rest_svr method
# File lib/Salesforce/rest/asf_rest.rb, line 186 def self.update(id, serialized_data_json, header=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@auth_header"), rest_svr=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@rest_svr"), api_version=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@api_version")) #Again the delete feature from ActiveResource does not work out of the box. #Providing a custom update function svr_url_4_http = rest_svr.gsub(/https:\/\//mi, "" ) #strip http:// prefix from the url. Otherwise, it will fail. if @@ssl_port.nil? @@ssl_port = 443 end http = Net::HTTP.new(svr_url_4_http, @@ssl_port) http.use_ssl = true class_name = self.name.gsub(/\S+::/mi, "") path = "/services/data/#{api_version}/sobjects/#{class_name}/#{id}" code = serialized_data_json # format -> Net::HTTPGenericRequest.new(m, reqbody, resbody, path, initheader) req = Net::HTTPGenericRequest.new("PATCH", true, true, path, header) resp = http.request(req, code) { |response| } # HTTP code 204 means it was successfully updated. 204 for httparty, '204' for Net::HTTP if resp.code != '204' message = ActiveSupport::JSON.decode(resp.body)[0]["message"] Salesforce::Rest::ErrorManager.raise_error("HTTP code " + resp.code.to_s + ": " + message, resp.code) else return resp end end
Public Instance Methods
Save the Object
, Note: there is an inconsistency between the Salesforce
REST JSON create object, which is just {“Name1”:“value1”,“Name2”:“value2”} where as the ‘save’ method of the ActiveResource
produces a JSON of {“Object Name”:{“Name1”:“value1”,“Name2”:“value2”}}. The Extra/missing ‘Object Name’ causes this to break. When this consistency is resolved, this method should be removed.
header = { "Authorization" => "OAuth " + @@oauth_token, "content-Type" => 'application/json' } rest_svr = 'https://na7.salesforce.com' api_version = 'v21.0' with v prefix
# File lib/Salesforce/rest/asf_rest.rb, line 120 def save(header=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@auth_header"), rest_svr=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@rest_svr"), api_version=Salesforce::Rest::AsfRest.send(:class_variable_get, "@@api_version")) class_name = self.class.name.gsub(/\S+::/mi, "") path = "/services/data/#{api_version}/sobjects/#{class_name}/" target = rest_svr + path data = ActiveSupport::JSON::encode(attributes) resp = Salesforce::Rest::AsfRest::call_rest_svr("POST", target, header, data) # HTTP code 201 means it was successfully saved. if resp.code != 201 message = ActiveSupport::JSON.decode(resp.body)[0]["message"] Salesforce::Rest::ErrorManager.raise_error("HTTP code " + resp.code.to_s + ": " + message, resp.code) else return resp end end