January 11th, 2008
After slogging through connecting Rails and Sugar via SOAP, I was tired and frustrated. The API is slow, and doing anything meaningful took a long time (ok, it took 30 seconds, but that seems slow to me; aren’t computers supposed to be fast?!). So, I came up with an alternative approach.
I know that Active Record (or whatever it’s called) in Rails is really just a fancy wrapper for the database. So, I created a second database connection, directly to the Sugar database!
You just have to setup new models and controllers in Rails. But, that’s not too hard. See this solution (http://pragdave.pragprog.com/pragdave/2006/01/sharing_externa.html). Use option 3. It worked well. Once you get the mapping figured out, you can even use the join tables, relationships, etc. It all works transparently.
I use this to synchronize various objects and fields.
Of course, you have to have access to the database. And, of course, I know I’m majorly in danger of screwing something up. And you have to figure out the inner workings of the Sugar database. And, of course, this might not work on the next version, etc., etc.
But, heck it is fast! And very easy to use!
If you want to know more, just let me know.
Posted in Ruby on Rails | 2 Comments »
January 6th, 2008
I have long wanted to make sure my CRM system (SugarCRM) and my project management system synchonized certain data, mainly company names. I hate having to sync stuff like that manually. So, I’ve been working on integrating the data using a SOAP client on the Rails side. It took all day to get this working. I don’t know why this took forever to find out, or why there aren’t many good references on the Web. (Maybe I’m just dense!)
I had to patch together a bunch of code, re-code some PHP examples, and do quite a bit of experimenting, to get this all working. Here is a list of some of the sites I used:
- http://www.sugarcrm.com/forums/showthread.php?t=17954&highlight=get_entry_list
- Good PHP examples about how certain SOAP calls are structured.
- http://www.ruby-doc.org/stdlib/libdoc/soap/rdoc/index.html
- Basics on how the SOAP objects work. Nothing really useful here, but it helped a little.
- http://www.beanizer.org/site/content/view/2/29/lang,en/
- Another good PHP reference.
- http://kousenit.wordpress.com/2006/08/08/ruby-web-service-clients/
- Has some general SOAP info, but not on SugarCRM
- http://www.sugarcrm.com/wiki/index.php?title=SOAP_in_RUBY
- Sugar’s own starter directions. This is the backbone of the code below.
- http://www.sugarcrm.com/wiki/index.php?title=SOAP_Documentation
- Sugar’s SOAP documentation. I have to admit that this doesn’t make a lot of sense to me.
- http://martyhaught.com/articles/2006/08/04/mapping-soap-response-without-wsdl/
- Good example of how confusing this can be. Note that Marty’s situation is exactly where I got stuck. It turns out that these “special” attributes in the SOAP Mapping Object response (__xmlattr, __xmele, etc.) are not really important to the programmer. You can access the data with special attributes that refer to the attributes returned from the server. At least that’s my theory. So, in my example below, you access the results you want using the “result.entry_list” attribute, because the “get_entry_list” command returns that variable. Note that when you examine the results object, you don’t see these special attributes. I’m sure this is some special Ruby thing that I don’t understand.
Anyway, here’s the code for getting a list of all companies, called “Accounts” in SugarCRM, into Rails in an array.
def list_accounts
require 'soap/wsdlDriver'
require 'digest/md5'
u = "username"
p = Digest::MD5.hexdigest("password")
ua = {"user_name" => u,"password" => p}
wsdl = "http://your-sugar-web-site.com/soap.php?wsdl"
#create soap
s = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
#uncomment this line for debugging. saves xml packets to files
#s.wiredump_file_base = "soapresult"
#create session
ss = s.login(ua,nil)
#check for login errors
if ss.error.number.to_i != 0
#status message
logger.debug "failed to login - #{ss.error.description}"
#exit program
exit
else
#get id
sid = ss['id']
#get current user id
uid = s.get_user_id(sid)
#status message
logger.debug "logged in to session #{sid} as #{u} (#{uid})"
#the part below is general. you can use it to get any type of data you want. just change the "module_name"
module_name = "Accounts"
query = "" # gets all the acounts, you can also use SQL like "accounts.name like '%company%'"
order_by = "" # in default order. you can also use SQL like "accounts.name"
offset = 0 # I guess this is like the SQL offset
select_fields = ['name','industry'] # this can't be an empty array, my testing showed
max_results = "1000000" # if set to 0 or "", this doesn't return all the results, like you'd expect
deleted = 0 # whether you want to retrieve deleted records, too
result = s.get_entry_list(sid,module_name,query,order_by,offset,select_fields,max_results,deleted)
#below is where we build the array of names. note that everything gets returns in a name-value pairs hash (name_value_list), using the field list from the request
@output = []
for entry in result.entry_list
item = {}
for name_value in entry.name_value_list
item[name_value.name]=name_value.value
end
@output << item
end
#logout
s.logout(sid)
#status message
logger.debug "logged out"
end
Posted in Ruby on Rails | 1 Comment »
December 16th, 2007
This is another one that should have been obvious. But, I was getting it wrong. Maybe it had something to do with upgrading to Rails 1.2.6.
Anyway, I was getting an error with a custom action. I was sending a form to “projects/do_something”. But, I kept getting the error of “Can’t find project with ID=do_something”.
This was happening because Rails thought it was supposed to be looking in the route for the show action. But, checking the routes file, I could see that I had defined my custom route. What, what was up?
It turns out, the custom route has to come before the standard “map.resources :projects” line.
Once I fixed that, all is well again. (I still think this acted differently in 1.2.3. Hmm).
Posted in Ruby on Rails | No Comments »
November 11th, 2007
I don’t know why this took a while to figure out, but it did. If you are using the stock Rails in_place_editor_field, you know it looks like this in the controller:
in_place_edit_for :user, :name
And like this in the view:
<%= in_place_editor_field :user, :name %>
This works fine so long as you’re rendering from the users controller. But, what if this view is a partial inside a different controller’s view? In that case, what gets called is not “/users/set_user_name” but “/othercontroller/set_user_name”. And, of course, it fails because there is no method (dynamic or otherwise) like that there.
The solution is easy, but the documentation isn’t helpful. You need to alter the view to be like this:
<%= in_place_editor_field :user, :name, {}, :url=>{:controller=>'users', :action=>'set_user_name', :id=>user.id}} %>
Posted in Ruby on Rails | 2 Comments »
October 21st, 2007
It took me a little while, but I finally got this working. You’ll need the iCalendar plugin.
require 'icalendar'
def view_ical
request = Net::HTTP::Get.new('/calendars/calendar.ics')
response = Net::HTTP.start('webdav.site.com') {|http|
request.basic_auth 'username', 'password'
response = http.request(request)
}
calendar_text = response.body
calendars = Icalendar.parse(calendar_text)
calendar = calendars.first
end
Posted in Ruby on Rails | No Comments »
September 23rd, 2007
Nested resources in Ruby on Rails are sort of neat, but they are a pain to implement. What’s more, I have to ask myself, why bother?
If a resource has a unique identifier id, then why would you need to call its parent resource to call it? The unique identifier is enough. And what resource doesn’t have a unique id these days?
Posted in Ruby on Rails | No Comments »
September 23rd, 2007
Geoffrey Grosenbach’s Ruby on Rails plugin calendar_helper is simple and easy to use. Maybe I’m just picky, but one part of it just wasn’t working right for me.
Originally, it looks like this on line 96:
cal << %(<caption class="#{options[:month_name_class]}"></caption><thead><tr><th colspan="7">#{Date::MONTHNAMES[options[:month]]}</th></tr><tr class="#{options[:day_name_class]}">)
It doesn’t really make sense for the month name to be in a TH tag and the caption to be empty. So, I put the month name in the caption and eliminated the extra table row. In the end I changed it to this:
cal << %(<caption class="#{options[:month_name_class]}">#{Date::MONTHNAMES[options[:month]]}</caption><thead><tr>)
This works well for me. If I knew anything about how to contribute to an open source project, I might propose a patch.
Posted in Ruby on Rails | No Comments »
September 23rd, 2007
This one is harder than it seems. But, I figured out a way. The trick and breakthrough came from Teflon Ted.
With a regular form, you could do this in your select statement:
:onChange=>"this.form.submit();"
This won’t work with a remote form, because the submission is not handled with the submit method but rather within the JavaScript callback in onsubmit. So, with a remote form, you have to change it to this:
:onChange=>"this.form.onsubmit();"
So, here is my code.
<%- remote_form_for
:user,
user,
:url=>{:action=>'update_remote', :id=>user.id},
:html=>{:id=>'form_'+user.id.to_s},
:loading=>"Element.show('spinner_"+user.id.to_s+"'); Form.disable('form_"+user.id.to_s+"')"
do |f|
-%>
<%= f.select
:project_id,
Project.find(:all).collect{|p| [p.name,p.id]},
{:include_blank=>false, :selected=>user.project_id},
{:onChange=>"this.form.onsubmit();", :id=>'user_project_id_'+user.id.to_s}
%>
<%- end -%>
>%= image_tag 'spinner_arrows.gif' %< Saving...
Note that this is in a partial that gets iterated over a collection. So, I have to give everything a unique id in the HTML. Also, note that this includes the user of a spinner to show activity is taking place. I also like to disable the form temporarily to make sure nothing else gets selected. I don’t have to hide the spinner or reactivate the form because when the table row gets regenerated via RJS, it goes back to the default condition.
Posted in Ruby on Rails | 3 Comments »
September 23rd, 2007
It seems like it would take a lot of work to get the in_place_editor to work in a partial on a collection, but it does. (It took me a lot of time to figure this out, but maybe I’m just more than average dense.) The best post to-date on this is at we eat bricks.
Just add the usual in the controller (user_controller.rb):
in_place_edit_for :user, :name
And, of course, the method:
def edit
@users = User.find(:all)
end
Then, in the main view (edit.rhtml):
<%= render :partial=>'user', :collection=>@users %>
Then, in the partial (_users.rhtml):
<%= in_place_editor_field :model, :column %>
At first, this won’t work. You will get an error that says “Called id for nil, which would mistakenly be 4 — if you really wanted the id of nil, use object_id” on the line containing the “in_place_editor_field”.
It turns out this is a bug, and there is a workaround. Just add this at the top of your partial:
<%- @user = user -%>
I hope this helps someone save some time.
Posted in Ruby on Rails | 3 Comments »
September 23rd, 2007
If you want to move your Wordpress permalinks via 301, you can try to do it by hand using rewrites in your .htaccess file. Much easier is Dean’s Permalinks Migration Plugin for Wordpress.
On my work blog (http://www.synaxisworks.com/blog/), I used to use the default “?p=post-number” format, and I wanted to change to a more SEO-friendly format. I setup Dean’s plugin. The first problem is that I didn’t know what to put for the “old permalink structure”. I tried a million combinations of text, regex, and Wordpress codes to try to get it to match the default format.
It turns out, according to this post, that the default permalinks never redirect and always work. So, the upshot is that I can’t redirect the default links and that I don’t really need Dean’s plugin at all. At least my new permalinks will be recorded in Google with the new format.
Posted in Wordpress | No Comments »