Archive for the ‘Rails’ Category

Master Pages for Rails (or, Heirarchial Layouts)

Friday, March 7th, 2008

One of the things that I like about the .net web application setup is the concept of Master Pages. The most common usage of this is if you have a Home Page that has a slightly different layot from the rest of the site, but you want to share the base DIV structure and assets without having to copy them into another layout… Keep it DRY!

Although there is no “out of the box” solution for sharing common layout setups in Rails except for using Partials, there is in fact a way of replicating this functionality. First, you need to be familiar with the ActionView::Helpers::CaptureHelper class and the methods in it.

So, what you do is create a container rhtml layout that contains the common layout elements, such as the base HTML and div structure.

container.rhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<body>
<%= yield :layout -%>
</div>
</body>
</html>

From there, you can create as many other layouts that reference that container, such as one called application.rhtml:
<% @content_for_layout = capture do %>
<div id='a_new_div' />
<%= yield :layout %>
<% end %>
<%= render 'layouts/container', { 'content_for_layout' => @content_for_layout } %>

Note what happens there – the capture method is used to catch the rendering of this layout file. Then, instead of just allowing it to render, this output is injected into the container.rhtml file. In this way, we have chained the inner layout (application.rhtml) into the outer (container.rhtml) layout.

In our example, the “<div id=’a_new_div’ />” will be injected, along with the data from the view, into the container. There is nothing stopping you from doing this to another layer, although I doubt how often you’d need to do that!

From our example above, we could also easily create a home.rhtml file that had slightly different layout from our application.rhtml file and use that from our HomeController without concern – all of the pages would then render in the correct layout while giving us the benefit of a shared outer container!

I have used this in production, and it works a treat both in terms of performance and code maintainability.

JRuby-OpenSSL and HTTP request timeouts (in ActiveSalesforce)

Friday, July 20th, 2007

So, JRuby looks pretty cool, and I’ve got some code written that uses a weird BouncyCastle encryption implementation going in my rails app. Works well, the WAR deployment works (with goldspike) and everything’s going swimmingly.

Until, of course, I tried to integrate with Another Project that uses the ActiveSalesforce. Behind the scenes, ActiveSalesforce makes SSL encrypted connections to Salesforce API endpoints and performs operations. This was working fine until I started the app under JRuby. All of a sudden, the salesforce connections stopped working.

A bit of digging later, and I discovered that the JRuby-OpenSSL implementation is causing reads of the HTTP responses to stall. JRuby HTTP is fine, Ruby HTTPS is fine, but JRuby HTTPS is not. Boo.

It’s a bug, now. I hope it’s fixed soon!

Integrating Log4r and Ruby on Rails

Saturday, June 16th, 2007

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!

Rails composite primary key support

Wednesday, June 13th, 2007

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.

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

Wednesday, June 6th, 2007

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.

Capistrano, Mongrel, and Mongrel_cluster Redux

Wednesday, June 6th, 2007

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

DhtmlCalendar and Piston

Wednesday, June 6th, 2007

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!

warning: already initialized constant OPTIONS

Monday, May 7th, 2007

Setting up my new computer now that I am settled in in London was turning out to be a right pain. I had ruby, rails, and postgresql installed, but my application was not starting.

I was getting the following error:

=> Booting Mongrel (use 'script/server webrick' to force WEBrick)
=> Rails application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
Exiting
/opt/local/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/commands/servers/mongrel.rb:15: warning: already initialized constant OPTIONS
/opt/local/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/commands/servers/mongrel.rb:18: undefined method `options' for []:Array (NoMethodError)
        from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:32:in `gem_original_require'
        from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:32:in `require'
        from /opt/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
        from /opt/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
        from /opt/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
        from /opt/local/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/commands/server.rb:39
        from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
        from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:27:in `require'
        from /opt/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
        from /opt/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
        from /opt/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
        from script/server:3

and lots more similar ones. I tried uninstalling Mongrel, reactivating old versions of rails, and so on. Nothing worked. A fresh rails application started ok though Searching online revealed nothing either, until I came upon a post about a gem not working on win32, and the solution was to remove that gem.

Ahhhhh.

I was missing gems. I installed every one that I had on my lappy, and everthing was cheerful again. Strange that the error message (even under webrick) did not report the problem clearly. In any case, problem resolved.

ActiveRecord::RecordNotSaved – before_save problem

Saturday, December 30th, 2006

I am in the middle of an update to my PeopleHub application and I started getting a weird error in my tests (yay for tests): ActiveRecord::RecordNotSaved

Part of the update was changing my before_save code to only do an expensive recalculation when it was required, and after doing so, setting the flag that it used to false (so that next time it didn’t do the expensive recalc). The code looked like this:

def before_save
  if self.do_update
    if x
      write_attribute("the_field", the_field_data)
      self.do_update = false
    elsif y
    end
  end
end

(please excuse the formatting. looks like my css needs attention)

So the end result of this is that in certain cases, the update is never done again. However, note that I am setting self.do_update = false at the end of the block. For those who remember their Ruby fundamentals (d’oh) they will know that if that line is the last that is evaluated in the block, it will return FALSE. As the docs say:

If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled.

Whoops. Thanks to Rick Olsen (http://threebit.net/mail-archive/rails/msg38644.html) for the help

gem, rake, webricks hangs – resolved! (damn you windows)

Sunday, September 3rd, 2006

You know you’re in for a fun day when you go to the code that you were working on yesterday and it stops working today.

In this case, I tried to start webrick to check my site, and the damn thing would not start. It would get as far as “=> Booting WEBrick…” and then hang. Ok, fine. Google a bit, maybe it’s the firewall? stop the firewall, no good.

Then, I tried to upgrade rails. ‘gem install’ hangs, before it says “upgrading source index”. Hrm. Must be something wrong with ruby. Try “gem list -r” which does not work on this machine but does work on my other workstation. Ok, got to be a ruby problem – upgrade ruby. no good. upgrade again. no good.

Then I uninstalled, rebooted, and reinstalled. “gem install” works! hooray! I install all the dependencies I need, and try to start webrick. Same bloody issue.

At this point, it’s fairly clear that it’s not a ruby or rails issue, it’s got to be a windows issue. I google for (out of desperation) “webrick hang” and I see, 4 down, a blog entry called WEBrick Server Hangs in Windows XP – have a look and it recommends running the following command to flush the Winsock Catalogue:

netsh winsock reset

And everything is fixed. Rake runs, webrick runs, gems still work. Bye bye 3 hours of my life. Thanks Windows. You’re a champ.