You need to sign in to do that
Don't have an account?

Ruby, SOAP, and "concrete entity type" error
Hi. I'm using the Ruby SOAP4r library with the Enterprise portal to try to add a new Opportunity. I create a new Opportunity object and add all the fields that SalesForce appears to require:
But I consistently see the error message "common.exception.ApiException: Must send a concrete entity type. (SOAP::FaultError)". I don't get it. What could be more concrete than an Opportunity? How can I find out what piece of information SForce is missing? Should I add more fields? Which ones?
Before you ask, yes, I've regenerated my WSDL files and rerun wsdl2ruby.
opp = Opportunity.new
class << opp
attr_accessor :accountId, :amount, :name, :closeDate, :stageName
end
opp.accountId = the_account
opp.amount = "3.14"
opp.name = "Test from script"
opp.closeDate = "2005-8-25"
opp.stageName = "Closed Won"
binding.create(Create.new([opp]))
But I consistently see the error message "common.exception.ApiException: Must send a concrete entity type. (SOAP::FaultError)". I don't get it. What could be more concrete than an Opportunity? How can I find out what piece of information SForce is missing? Should I add more fields? Which ones?
Before you ask, yes, I've regenerated my WSDL files and rerun wsdl2ruby.
How are you using wsdl2 ruby? I was trying the following with soap4r version 1.5.4:
VERY happy to see someone else trying to use ruby with sforce.
Any tips will be very much appreciated.
Now, for the session header -- I saw some sample code somewhere that looked like this:
So here's how I fit that fragment into a semi-working program:
Notice that I cheated a little. The SOAP binding just refused to fill in the body of the SessionHeader, no matter how many different permutations I tried of passing in the header (string, SessionHeader, SObject, etc.). So I just generated a little XML fragment myself. This is a terrible strategy, by the way -- the real solution is to fix soap4r.
You've made my day. :-)
at depth 1 - 20: unable to get local issuer certificate
/usr/lib/ruby/site_ruby/1.8/http-access2.rb:970:in `connect': certificate verify failed (OpenSSL::SSL::SSLError)
Thanks!
Todd Breiholz
I've never seen that error -- I'm not familiar with it. Looks like it's happening down in the https libraries. The only thing I can think of is to post to Ruby-talk and see if they've heard of anything like this.
Anyway, stay tuned -- a SalesForce-specific Ruby binding is coming soon on RubyForge.org.
--undees
cleanly (without directly munging the xml).
I'm still experimenting, but hope to post some basic "from scratch" cookbook information
for using sforce with ruby soon.
the ca.pem certificate and soap/property file as shown in Nakamura-san's sample
Then ssl worked fine for me.
Notes on using sforce with ruby
First download the sforce API documentation from http://www.sforce.com/us/docs/sforce60/sforce_API.pdf
Next download latest version of http-access2 from http://raa.ruby-lang.org/project/http-access2.
Install http-access2 with:
Download the latest version of soap4r from http://raa.ruby-lang.org/project/soap4r
Install soap4r with:
Copy the wsdl2ruby.rb and xsd2ruby.rb scripts someplace useful:
Make a working directory for your project:
Download the enterprise wsdl from salesforce.com. I think you need to login to salesforce as an administrator (alternately get a developer login on the sforce site and download the partner wsdl file). After logging in, go to "Setup" (upper right hand corner) then to "Integrate" (left-hand navigation) then to "WSDL Generator". Save the resulting file as ~/work/myproj/enterprise.wsdl.xml.
Create the ruby bindings with:
This creates the following files:
The sample client isn't terribly useful as is, because the sforce api requires you to change the default endpoint and rewrite the session id in the SOAP header before you can use the API.
I created a new driver file called "sforceDriver.rb" that contained the following:
Now you need to create a certificate file and tell soap to use it.
Now create your client application file. The following sample generates a list of accounts for your enterprise:
Running this program generates output like:
I was using "https://na1-api.salesforce.com/services/Soap/c/6.0" as my endpoint_url.
The API says to use the endpoint URL that is returned after the call to login using the default url. This was the na1-api URL above. Unfortunately, however, there doesn't appear to be any way to change the endpoint URL after calling Soap.new (at least none that I can figure out).
Note, too, that it seems you can't call query with a simple string. This was a surprise to me.
I'm also not sure what the calloptions stuff is for, either, but it was in Nakamura-san's example so I left it.
I'm rapidly becoming allergic to SOAP. All these extraneous calls to a "result" method seems overly verbose to put it mildly. The last line in client.rb just cries for yet another wrapper method -- it would be nice if wsdl2ruby.rb just did all this for you. It feels like the "2ruby" part is only halfway there -- I want to use RUBY strings as parameters to query() and I want to have accessors that return normal RUBY objects.
To add insult to injury, you can't even run the debugger on the client program above, even though it runs fine outside of the debugger:
Bah!
Notes on using sforce with ruby and soap4r
First download the sforce API documentation from http://www.sforce.com/us/docs/sforce60/sforce_API.pdf
Next download latest version of http-access2 from http://raa.ruby-lang.org/project/http-access2.
Install http-access2 with:
Download the latest version of soap4r from http://raa.ruby-lang.org/project/soap4r.
Install soap4r with:
Copy the wsdl2ruby.rb and xsd2ruby.rb scripts someplace useful:
Make a working directory for your project:
Download the enterprise wsdl from salesforce.com. I think you need to login to salesforce as an administrator (alternately get a developer login on the sforce site and download the partner wsdl file). After logging in, go to "Setup" (upper right hand corner) then to "Integrate" (left-hand navigation) then to "WSDL Generator". Save the resulting file as ~/work/myproj/enterprise.wsdl.xml.
Create the ruby bindings with:
This creates the following files:
The sample client isn't terribly useful as is, because the sforce api requires you to change the default endpoint and rewrite the session id in the SOAP header before you can use the API.
I created a new driver file called "sforceDriver.rb" that contained the following:
Now you need to create a certificate file and tell soap to use it.
Now create your client application file. The following sample generates a list of accounts for your enterprise:
Running this program generates output like:
I was using "https://na1-api.salesforce.com/services/Soap/c/6.0" as my endpoint_url.
The API says to use the endpoint URL that is returned after the call to login using the default url. This was the na1-api URL above. Unfortunately, however, there doesn't appear to be any way to change the endpoint URL after calling Soap.new (at least none that I can figure out).
Note, too, that it seems you can't call query with a simple string. This was a surprise to me.
I'm also not sure what the calloptions stuff is for, either, but it was in Nakamura-san's example so I left it.
I'm rapidly becoming allergic to SOAP. All these extraneous calls to a "result" method seems overly verbose to put it mildly. The last line in client.rb just cries for yet another wrapper method -- it would be nice if wsdl2ruby.rb just did all this for you. It feels like the "2ruby" part is only halfway there -- I want to use RUBY strings as parameters to query() and I want to have accessors that return normal RUBY objects.
To add insult to injury, you can't even run the debugger on the client program above, even though it runs fine outside of the debugger:
Bah!
Have you been able to create / update objects yet?
Heh. Thanks, but I didn't do anything smart -- I just pieced together all the bits of information that were strewn about here (from you!) and on the soap4r site by NaHi (Nakamura-san). I thought it would be useful to put together a single document (to prevent anyone else from having to go through the same amount of pain for the same "baby step" result).
I called it a night after getting a simple query working, but I'll try to get an update working today.
Anyway, I think I'll join your rubyforge project and communicate further there.
Our latest wire trace follows -- we're still getting the INVALID_TYPE "Must send a concrete entity type" error. I must be missing something, but the type stuff in the wiretrace looks pretty much identical to the sample at http://www.sforce.com/us/resources/soap/sforce60/sforce_API_messages_create.html
Where are we messing up?
Immediate and perfect response as usual. Don't you ever sleep?!!
Many thanks!
The librarys that come with 1.8.2 don't detect the characterset that SF sends it's soap messages in. I do not know if this is fixed in the current 1.8.4 release, but just put this near the top of your sforceDriver.rb file.
XSD::Charset.encoding = 'UTF8'
Also, had to apply a fix to the soap4r library:
http://dev.ctor.org/soap4r/ticket/152
And while most might get this(I'm extremely new to ruby), the ca.pem file does NOT go into the soap directory.
I believe that is all I did to get things working and now all QUERYS well.
I can't do:
myAccount = Account.new
myAccount.Name = "My Company Name"
because .Name doens't exist. And I can't pass anything to .new either.
Any suggestions or weird hacks are acceptable. Once the ActiveSalesforce project has a demo I'll probably move to that, but in the mean time...
Thanks!
Message Edited by portrman on 02-07-2006 03:33 PM
ActiveSalesforce (ASF) is up and ready to to try out (I am about to move the project into Beta). You do not need to use all of Rails (its very cool though) to take advantage of ASF as a powerful interface into salesforce. We are in the process of developing some demos - more for marketing than for developer education at this point because if you know Rails you know most of what you need to know to use ASF. We will also have live demos up and running from the ASF hosted site at activesalesforce.textdriven.com.
The new home page just went up over the weekend (http://activesalesforce.textdriven.com/) that includes the simple instructions to get you up and running quickly. ASF is gem installable - in fact you can start with a naked Ruby w/ gem box and with just:
you will get everything you need (including rails itself).
I would love to get more info/details from you on what type of information you need to be successful using ASF!
BTW - Initially during development of ActiveSalesforce I ran into all of the same issues with soap4r - and different sets of issues from one release of Ruby to the next. So much so that I ended up trying out and loving rforce (see http://rubyforge.org/projects/rforce/) and have added some mods to rforce (still to be committed). In a nice bit of symmetry the author of rforce is one of the early adopters of ASF.
Chris
The biggest thing I need is a working example RoR application. I started using RoR and Ruby for the first time last week, so I don't even know how to use ActiveSalesforce in RoR. My experience with the SF api is in .NET so I have an idea of what examples I would be interested in.
Creating/Updating/Deleting Accounts, Contacts, etc
Any special handling of DateTime's ? .NET doesn't allow DateTime to be nullable so there was a _cSpecified property for those.
Querying .. Ruby way of using queryMore(). Apparently C# benefits from being asynchronous when using queryMore.
My needs are actually very basic at the moment, however so are my Ruby and Rails skills.
One other note. I'm using the SF 7.0 api. But I don't think this is a problem as I didn't see anything in your setup example about providing a wsdl file.
I've very excited about ActiveSalesforce as well. Hopefully SF/sforce will add a section for Ruby soon.
The development process is essentially indistinguishable from building a rails app using any other backend (some optional features like Transactions are not supported because the sforce api does not support transactions).
Basically:
- use:
rails my_app
to generate the skelton for development of my_app (feel free to use the name 'depot' if you are following the sample app in Agile Development Using Rails)
- follow the directions on http://activesalesforce.textdriven.com/ on how to configure (involves modifying my_app/config/environment.rb and my_app/config/database.yml)
that's the end of the ASF specific bits. Then
- use:
ruby scripts/generate scaffold Account
to generate the scaffolding for your salesforce.com Account object
- ruby scripts/server
point you browser at http://localhost:3000/accounts and you should see the list of accounts for your org.
edit, show and create should all be fully functional also.
The rails approach to things is quite a bit different (and very pleasant) from the classic
jdbc/soap/odbc way of doing things. For example, you do not deal with wdsl to work with salesforce at all - in fact for the most part you can do quite a bit w/out ever seeing any SOQL and you will definitely not interact with soap bits like wdsl. All metadata is dynamically handled (things like describeSObject do happen under the covers but that is part of ASF). Fields are automatically added at runtime to your model (ActiveRecord::Base subclasses). Relationships are also automatically added to your model (this is an enhancement over most RoR connectors that typically stop at exposing fields automatically).
http://www.pragmaticprogrammer.com/titles/rails/index.html will get you started fast (in just a couple of chapters).
I have asked to have a new board just for Ruby & RoR created asap - we do need our own space.
Nothing special should be needed for various data types like datetimes (if you run into any please log a bug at http://rubyforge.org/tracker/?group_id=1201).
Now comes the next step. I realize most of problems come from a lack of knowledge about RoR but I'm working, not just leaching for answers, promise :)
So far I've been working in a seperate RoR application. Now I need to take what I've learned and integrate SF integration into our app that is written using Rails. Because Rails really likes it's naming conventions, I can't use just "Contact" or "Account" like SF does because our web app already uses those names. So instead I created a Sfcontact (note: ruby wanted that casing, personally I prefer SFContact). Here are the steps I ended up using.
Add SF database connection under "development:" in database.yml
Removed the connection to my MySQL db.
ruby script/generate contact (it connects to SF (because I did the switch in the database.yml file) and generates the controller, helper, views, etc)
Added mysql db connection info back
Placed SF connection under "sf_development" and "sf_production"
Repaced "Contact" with "Sfcontact" everywhere required by Rails
Add set_table_name "contact" to model
Add establish_connection "sf_development" to model
When I try /sfcontact/list I get a "uninitialized constant Contact" from dependencies:200 when trying to load contact.rb. My guess is, is that Rails is trying to include the model "contact.rb" so it can create a new instance of that model.
So what am I missing? I will need to do this for several of the others like "Account" and then would like to maintain the naming convention of SfAccount, SfAsset, Sfcontact if possible.
Thanks. This really is awsome work!
require 'rubygems'
require_gem 'activesalesforce'
# begin stubbed in functionality
class Logger
def initialize
end
def debug message
puts message
end
end
module ActiveRecord
Base.logger = Logger.new
module ConnectionAdapters
class SalesforceAdapter
def log sql, name
yield sql, name
end
end
end
end
# end stubbed in functionality
# now for the real script
ActiveRecord::Base.establish_connection(
:adapter => "activesalesforce",
:username => "INSERT-YOUR-USERNAME-HERE",
:password => "INSERT-YOUR-PASSWORD-HERE"
)
# Define the class we want to introspect from. Ruby does a
# tremendous amount of introspection so we're relieved of the
# burden of creating setters and getters.
class Lead < ActiveRecord::Base
end
# Here's a very simple query to get all our leads from Salesforce
all_my_leads = Lead.find(:all)
# Loop through each of my leads and ask it for the contents so i
# can see what's inside.
all_my_leads.each do |lead|
puts lead.inspect
end
Message Edited by matt.ho on 03-12-2006 05:08 PM
Message Edited by matt.ho on 03-12-2006 05:09 PM