Categories
log4r Rails

Integrating Log4r and Ruby on Rails

Aaaaaaaages ago, I wrote a message on the mailing list (before it moved to Google Groups!) about how to integrate Rails and Log4r. Since then a little bit has changed and that way may or may not entirely work any more. Since then, aaaaages ago Jason Rimmer asked me to update so that it’s all new and fresh, but I completely forgot in the move to the UK (very sorry Jason!). So here it is.

I’ve got a few outputters. One that acts like the default outputter, that writes “development.log” and so on. Then another that outputs to standard error for console lovin’ (in dev mode). Then another that uses a date file outputter to automatically roll over logs every day (for production mode), and finally an Email outputter that only runs in production and sends an email of the log for ERROR and FATAL log levels.

Log4r Rails configuration files

The first bit is the configuration YAML file, which is used to configure the loggers. Then there is logger.rb, which turns on and off the outputters as required. The final part is to include this logger.rb into the application configuration.

It is VERY IMPORTANT that you include the file before the call to the Rails::Initializer.run do block. This is because in this section of code the RAILS_DEFAULT_LOGGER is initialised, and if we don’t get in before that, we won’t get our logger injected into the Rails framework stack. So, configure it like this:

require File.join(File.dirname(__FILE__), 'boot')

require File.expand_path(File.dirname(__FILE__) + "/logger")

Rails::Initializer.run do |config|
...

Just drop the require line in there and it will load logger.rb, which loads log4r.yaml, and everything is up and going. You’ll see friendly [DEBUG] lines in your console and everthing! Of course, I prefer verbose logging on the console in development; you may not, customise by reading the log4r manual. Of course, if you expect your error mails to be delivered, change the SMTP server settings at the bottom of the yaml file.

Sorry for the delay Jason!

Categories
Rails

Rails composite primary key support

I am working with a legacy database. Usually, the built in rails stuff for table prefixing and primary key changes is enough. Sometimes, it’s not.

I had a problem with a join table that has Foreign Key names that are tablename_id, but the tables they reference is tablename_id as well. The has_and_belongs_to_many method DID NOT like it at all. Added to this is that there are attributes in the join table (is_primary) that I need to use. I considered (and discussed with the Java devs) the option of making the join table have an ID and making it a model, but there was potential for breakage and I like to tred very carefully around the existing app and making changes.

So, a bit of time on Google later, and I came across Nic Williams’ Composite Primary Key plugin. Oh man, it works a treat. I created the model for the join table, specified the primary keys, and went as normal!

Beautiful.

Categories
Uncategorized

WordPress <code> and <pre> formatting

After the last paste-heavy post, I finally got around to doing something about wordpress’s formatting of code blocks. This site was very helpful:

http://tjulo.blogspot.com/2007/03/wordpress-and-source-code-posts.html

So, edit the file wp-includes/js/tinymce/plugins/wordpress/editor_plugin.js.

Comment out the section that replaces pre content:

/* var startPos = -1;
while ((startPos = content.indexOf('', startPos+1);
var innerPos = content.indexOf('>', startPos+1);
var chunkBefore = content.substring(0, innerPos);
var chunkAfter = content.substring(endPos);

var innards = content.substring(innerPos, endPos);
innards = innards.replace(/\n/g, '
');
content = chunkBefore + innards + chunkAfter;
}*/

Then I had to update my CSS so that pre used the same class as code and then change my posts over to use pre instead of code.

Next step is to fix code too so that I don’t have to think about it.

It does seem to have the side-effect of not automatically handling the escaping of < and > symbols outside those tags though, which for this post where I started with <code> and <pre> instead of code and pre, made things a bit of a mess.

Categories
Rails software development

Rails ActionWebService SOAP error “No valid method call – missing method name”

For a Salesforce.com integration project, I need to create a SOAP server to accept messages from Salesforce. Seeing as there is no way directly import a wsdl into ActionWebService, I instead used wsdl2ruby from the soap4r distribution to generate server stubs. Then, I used ActionWebService to emulate the same service. I had problems with using the default layout, so I changed my structure to use a delegated structure:

class NotificationServiceController < ApplicationController
  web_service_dispatching_mode :delegated
  web_service_scaffold :invoke
  web_service :notifications, NotificationService.new
end
class NotificationServiceApi < ActionWebService::API::Base
  inflect_names false
  require_soap_action_header false
  api_method :notifications,
             :expects => [Notifications],
             :returns => [:bool]
end
class NotificationService < ActionWebService::Base
  web_service_api NotificationServiceApi
  def logger
    RAILS_DEFAULT_LOGGER
  end
  def notifications(organization_id, action_id, session_id, enterprise_url, partner_url, notification)
    my_object_id = notification.sObject.id
    ack = false
    begin
      ack = so_something(my_object_id)
    rescue Exception => e
      logger.error("Error processing payment: #{e.message}")
    end
    ack
  end
end

But STILL SOMETHING WAS WRONG. I was getting "No valid method call - missing method name" with the Salesforce outbound message queue reporting "org.xml.sax.SAXParseException: Content is not allowed in prolog." MMmmmmm helpful. The stack trace was showing that rails was trying to process the request as XMLRPC not SOAP, which was all wrong.

The stack trace looked something like this:

RuntimeError (No valid method call - missing method name!):
    /usr/lib/ruby/1.8/xmlrpc/parser.rb:476:in `parseMethodCall'
    /usr/lib/ruby/1.8/xmlrpc/marshal.rb:63:in `load_call'
    /usr/lib/ruby/1.8/xmlrpc/marshal.rb:32:in `load_call'
    /vendor/rails/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb:36:in `decode_request'
    /vendor/rails/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb:32:in `decode_action_pack_request'
    /vendor/rails/actionwebservice/lib/action_web_service/protocol/discovery.rb:20:in `discover_web_service_request'
    /vendor/rails/actionwebservice/lib/action_web_service/protocol/discovery.rb:18:in `discover_web_service_request'
    /vendor/rails/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb:49:in `dispatch_web_service_request'
    (eval):1:in `notifications'
..........

Then, I came across patch 7077 (indirectly via this and then this), so, using my new best friend Piston I checked out Rails 1.2.3 into vendor/rails, and patched with the diff in the change. It was not entirely smooth - the xmlrpc.rb file could not be patched, but I merged the change manually.

All done! Works!

One thing I did discover the hard way though is that you need to have the whole stack of definitions with the same naming scheme for this to work. That is, if you've got a NotificationServiceController, you need to ensure that you have a NotificationService and a NotificationServiceApi defined and in use - no other class names will work. No Reuse of API Definitions, which is a bit of a bugger.

Categories
hosting Rails

Capistrano, Mongrel, and Mongrel_cluster Redux

Over a year ago, I wrote a post about how to get the then-new Mongrel_cluster working with Capistrano. Since then, I have not had to touch my deployment config again.

2 days ago I needed to do a new deployment config and I thought I’d look at my config again. In reflection, it a bit dodgy, but at the time it was the best way! Honest! Also I note that in my original post, there’s broken links, and also that it is still far and away the most popular content on my site (direct links were almost 25% of the traffic!), so best to make it all new-like.

What do you do these days then?

  1. Get yourself mongrel and install the mongrel_cluster gem too:
    # sudo gem install mongrel mongrel_cluster –include-dependencies
  2. Go to the root of your Rails app
  3. Get a mongrel_cluster config:
    # mongrel_rails cluster::configure -e production \
    -p 8000 \
    -a 127.0.0.1 \
    -N 3 \
    -c /path/to/the/application’s/current
  4. Open up the /config/deploy.rb file and add:
    require ‘mongrel_cluster/recipes’
    set :mongrel_conf, “#{current_path}/config/mongrel_cluster.yml”

You’ll still need to add the @restart task something like this to ensure that the app comes up with the box:

@restart cd /path/to/the/application's/current && mongrel_rails cluster::start

Use cap cold_deploy to launch your app for the first time, and cap deploy to redeploy (cap deploy_with_migrations for your db updates too.)

Then all you need to do in configure your favourite proxy to serve the app from ports 80/443/whatever, and you’re good to go. I am using Apache 2.2, but perhaps soon I’ll have time to set up Swiftiply

Categories
Rails software development

DhtmlCalendar and Piston

Over the weekend I decided to try (again) to find a Rails plugin for a Dhtml Calendar. The previous one I tried relied on an Engine, and for some totally unreasonable errrrrrrrr reason, I don’t like that. So I came across this: http://dry.4thebusiness.com/info/dhtml_calendar. At first it was all sunshile, lollipops and rainbows, but I soon realised that the plugin did not like Firefox.

This was, of course, a right pain. A quick test in IE determined it worked fine. In Firefox, it popup worked, but when you select a date the select boxes did not get updated. I waded through the javascript that comes with the plugin, and it seemed ok, but it simply WAS NOT firing in Firefox.

After some Javascript mangulation (that’s my word but you can use it if you want) I figured out that it wasn’t picking up the HTML form. So, even though the documentation says:

“Note: :form_name is optional unless your form is named. If it is named then supply the name of the form.”

I included it anyway.

And it worked. Yay.

Also, in the past I have used svn:externals to include external plugin into my project, and at the most inopportune time the external site as either (and I have had both of these happen):

  1. The external site is inaccessible at deployment time, meaning that your site is offline, or
  2. The external site updates the codebase to suit a new Rails version that you have not upgraded to, meaning that your site is broken and once again, offline

After doing that once or twice, I gave up on svn:externals and just exported the remote source and checked it into my repository, which is a bit shit because it removes the link to the origin of the code. This time I used Piston.

Piston fixes this. It checks out the remote code as an svn export but it stores the synchronization information as svn properties so that it can later be updated, or locked, or even merge the remove changes wth your own changes. Spiffy!