NoMethodError (undefined method `finder’) with Engines and Rails 2.2

January 19th, 2009

I was getting this error with Rails 2.2 when using ActionMailer.

NoMethodError (undefined method `finder’ for #<ActionView::Base:0×34146fc>)

It stems from a line in engines/lib/engines/rails_extensions/action_mailer.rb

This is some problem between Rails 2.2 and Engines. Reinstalling engines didn’t seem to help.

Simply put, you need to go here and apply this patch:

http://github.com/lazyatom/engines/commit/499ce3b0480d8fa9375203f5efcadb8cf6ea9efe

This took me hours to figure out. I don’t know why there isn’t any more help on this problem.

Rails + SugarCRM - An alternative approach

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.

Rails + SugarCRM + SOAP - Get a list of Sugar accounts into Rails as an array

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

Place Custom Rails Routes First

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).

Ruby on Rails: Using a different controller with in_place_editor_field

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}} %>

Rails: Parsing iCal calendar on a password-protected WebDAV server

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

Nested resources in Ruby on Rails: why bother?

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?

Ruby on Rails Calendar Helper doesn’t quite work for me

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.

Getting a remote form to submit within a partial collection when any select changes in Ruby on Rails

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 -%>

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.

In_place_editor with a collection in a partial in Ruby on Rails

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.