Wednesday, May 27, 2009

Exception notifier plugin causing internal server error

I am using the exception notifier plugin to send me emails on the details of all unhandled exceptions in my web app (read about this plugin on my earlier blog posting, Exception notification plugin).  I recently put my web app on a new server, and when an unhandled exception occurred, Internal Server Error was displayed to the user, and no email was sent.  After digging in to this, I found that the exception notification code itself was generating an exception.  The offending file is views/exception_notification/_environment.rhtml.  Turns out there is a syntax error in that file when using Ruby 1.8.6 patch level 110 or higher.  The plugin was fixed in November 2007, but I had downloaded the plugin before that time.  

The fix is described at http://dev.rubyonrails.org/ticket/9940.  Simply edit the plugsin/exception_notification/views/exception_notification/_environment.rhtml file, and change the third line to:
* <%= "%-*s: %s" % [max.length, key, filter_sensitive_post_data_from_env(key, @request.env[key].to_s.strip)] %>



The only difference is that the first *- is changed to -*.

Wednesday, May 13, 2009

Running the same rake task more than once

While writing some rake tasks, I found out that you cannot run another task more than once in your task.  Example:
task :test do |t|
Rake::Task["log:clear"].invoke
# do something to add to the log file
Rake::Task["log:clear"].invoke
end

No errors will occur, but the second log:clear will not get run. All rake tasks work like this. I'm not really sure of the reason why this capability was put in rake, but rake keeps track of when each task gets run and only allows a task to be run once within the same rake call. But, to get around this, you can call reenable on the task after it's invoked, and then the task can be used again. Example -
task :test do |t|
Rake::Task["log:clear"].invoke
Rake::Task["log:clear"].reenable
# do something to add to the log file
Rake::Task["log:clear"].invoke
end

The second log:clear will now run correctly. Another wonderfully documented feature of Ruby....

Thursday, April 16, 2009

Converting a string to a time in Ruby

I had a really hard time finding information on how to convert a string in your own custom format into a Time object in Ruby. Turns out it's pretty easy but poorly documented. Use the method DateTime.strptime. Documentation on that is hard to come by, but you pass in the string containing the time as the first parameter, then the second parameter is the format string. This returns a DateTime object, call .to_time on it to get a Time object. Example:
DateTime.strptime("2009/04/16 19:52:30", "%Y/%m/%d %H:%M:%S").to_time

The format uses the same syntax as what you pass in to strftime to print out a date. The page http://snippets.dzone.com/posts/show/2255 has a complete listing of all format types.

Friday, January 9, 2009

How to debug Javascript in Internet Explorer

Firebug for Firefox is an invaluable tool for debugging Javascript.  And when you're writing code that uses the Prototype library, the code usually works the same in both Firefox and Internet Explorer, so can use Firebug to debug your Javascript.  But for regular, non-Prototype Javascript code, and the occasional Prototype function that isn't completely browser independent, you may need to debug Javascript code from Internet Explorer to get it to work correctly.  Fortunately it's pretty simple to do this, although it's not easy to find how to do this.

Before you can start debugging, you will need either Visual Studio or Microsoft Script Editor.  If you don't have Visual Studio, you can download the Microsoft Script Editor from Microsoft at http://www.microsoft.com/downloads/details.aspx?FamilyID=2f465be0-94fd-4569-b3c4-dffdf19ccd99&displaylang=en.  From Script Editor, you can do just about everything that you can from Visual Studio, including viewing the call stack, setting break points, stepping through code, setting variables to watch, etc.


Once you have Visual Studio or Script Editor installed, from Internet Explorer, click Tools, then Internet Options.  (if you're using IE7 and the menu bar is hidden, press ALT to show it).  From this window, click the Advanced tab, and then uncheck "Disable script debugging (Internet Explorer". 


Once you click OK here, go to the page that you wish to debug from.  Then click View, Script Debugger, Open (again if you're using IE7 and the menu bar is hidden, press ALT to bring it up).

After this another window will open up asking which debugger you wish to use.  Click on the one you wish to use (either Script Editor or Visual Studio), and click Yes.


If you use Script Editor, the HTML for the page you are on will be displayed.  This typically doesn't help you debug the Javascript because your Javascript is probably in another file.  But by default there is no window to select other files!  To show the file selection window, simply click Debug, Windows, then Running Documents.

This will open up a window on the left listing all of the loaded Javascript and HTML files.  Just double click on the file that your code that you wish to debug is in.  Now you can set a breakpoint on a line by clicking in the gray area directly to the left of the code (or click Debug, New Breakpoint), and when you do something from the web page that will cause this Javascript to run, the Script Editor will pause execution from that line, allowing you to inspect values, view the call stack, step through code, etc.  If you want to debug code that runs when your document loads, you can add the line debugger; to your Javascript, which will cause the debugger to automatically open up when the page is loaded. 

While this capability isn't as comprehensive as Firebug (no viewing of requests, times, etc.), it certainly serves the purpose of allowing you to debug Javascript code from within Internet Explorer.  

Saturday, December 27, 2008

Status 500 when calling any action on a controller

The other day I added a new controller, and any time I browsed to anything in that controller, the web browser displayed a status 500 Internal Server Error.  There was no debug screen.  I looked in the development log file, and this showed up:

/!\ FAILSAFE /!\ Mon Dec 22 14:13:51 -0500 2008
Status: 500 Internal Server Error
wrong number of arguments (1 for 0)

with a full call stack. After digging around Rails code and looking around on the Internet, I finally figured out what the problem is. You can't have a method called send in a controller. After I renamed the send method to something else, everything worked.

Monday, November 24, 2008

Database Migration Can't Assign/Update Newly Created Columns

I wrote a database migration today that I ran in to some problems with.  The migration simply adds a column to a table, and then assigns a value to the new column.  All appeared to work when the migration ran.  But, when I checked the database afterwards, the column was added to the table but the value that I assigned was not set.  Here is my example:

class AddAndSetColumn < ActiveRecord::Migration

def self.up
add_column :nodes, :new_column_1, :boolean, :null => false, :default => false

Node.find(:all).each do |n|
n.new_column_1 = true
n.save!
end

end

def self.down
remove_column :nodes, :new_column_1
end
end


After running the migration, and looking at the database, all nodes had new_column_1 set to false, even though I explicitly set it to true in the migration.

After searching around to see why this happens, I found a posting that described this problem at http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/573cbb96b84f3306/a0d6a3c7dddbbbcb?lnk=raot. The solution for this is to call reset_column_information on the model for the table that you added the column to before you assign values. So I changed my migration to:
class AddAndSetColumn < ActiveRecord::Migration

def self.up
add_column :nodes, :new_column_1, :boolean, :null => false, :default => false
Node.reset_column_information

Node.find(:all).each do |n|
n.new_column_1 = true
n.save!
end

end

def self.down
remove_column :nodes, :new_column_1
end
end


And it works!

Sunday, November 23, 2008

Using ICE with Ruby on Rails

For those of you who have never heard of it, ICE (Internet Communications Engine) is a really good object oriented middleware platform for communication between applications written in different languages running on different platforms. ZeroC is the company that makes ICE, you can find out more about it at www.zeroc.com.

I've used ICE on mulitple projects for communication of actions to take between the Ruby on Rails web server, and a C++ backend application that performs the actions. I would highly recommend it, if you have any backend application (C++, Java, C#) that you need your Ruby on Rails application to communicate with.

For the most part, setting up ICE to work with Ruby on Rails is pretty simple. If your server is Linux, download the appropriate RPM from ZeroC's site, or download the source code and compile it. For Windows, download and install the ICE for Visual C++ 6.0 file (Ruby support is not in the Visual Studio 2005 or 2008 installation, the C++ 6.0 package can be installed along side either of these).

After this, add the /ruby directory of the ICE install to your RUBYLIB environment variable. This is the directory that Ice.rb gets installed to. For a Linux install, a common location is /opt/Ice-3.3.0/ruby. Then add the /bin directory of the ICE install to your PATH environment variable. Example for Linux installs - /opt/Ice-3.3.0/bin.

After those are added to your environment variables, you should be able to add
require "Ice"
to your Ruby on Rails code to start working with ICE. I typically use slice2rb from the command line to produce a .rb file from my slice definition file before hand, but you can also call slice2rb directly from Ruby. If you do things the way I do, add a require for your slice2rb produced Ruby file.

You must initialize the Ice engine ONCE in your server process. Originally, I was initializing it and destroying it on every action that used Ice. This seemed to work fine for a while, but then I started having strange memory issues in my server related to Ice. I took out the initialize and destroy on every action, and only initialized once, and this cleared up the strange issues.

So what I would recommend is that you make a class variable to hold the Ice runtime in either the controller that calls Ice (do it in application controller if more than one controller calls Ice), or make a separate class to handle Ice. Here is an example of what should be placed at the top of this class (application controller used as an example:
require 'Ice'

class ApplicationController < ActionController::Base

@@ic = nil


Then, for EVERY controller action where you are calling an ICE method, you must do something similar to this
@@ic = Ice::initialize() unless @@ic
proxy = SliceModule::ServerObjectPrx::checkedCast(@@ic.stringToProxy("ServerObject:tcp -h #{server_name} -p #{server_port}"))
# any actions on the server object proxy