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

Thursday, September 11, 2008

My new Roomba bumps into dark furniture

I wasn't sure what blog to post this to, but I thought it worthy of being posted.  I just recently got a Roomba for my condo.  Having two cats with mostly hardwood floors creates a lot of "cat hair tumbleweed" as I call it.  Those of you who have cats with hardwood floor know what I mean.  I figured the Roomba would be an ideal solution for keeping my floors clean, and since I live my condo is one level, the Roomba will be able to clean everything.  

The Roomba works better than what I was even expecting, except for one pretty serious problem.  The Roomba has sensors which "see" objects in front of it, so that way it will slow down before bumping in to them.  This sensor works great for my walls, but it doesn't seem to see most of my furniture and bumps in to it at full speed.  It seems like it doesn't see anything that's dark brown or black, which makes sense since it uses infrared to see.  After the first time I let Roomba run free, I noticed a nick in the leg of my entertainment center.  I also noticed a little wood splinter by my dresser that I can't figure out where it came from.  Both of these were definitely from the Roomba, when it hits the furniture it's going fast enough to do some damage.   
After reading a few web sites, I found a solution for this.  Buy rubber sponge tape, and attach it all the way around the front bumper of the Roomba.  That way, the rubber sponge will absorb the impact when the Roomba hits stuff at full speed.  So far this has worked great!  Here is a link to the roll of 1/4 inch thick, 3/4 inch wide, 10 foot long rubber tape that I bought from Hardware and Tools:
Make sure when you attach the rubber tape that you attach it at the bottom of the bumper, it shouldn't cover the sensors.  As I learned the hard way, 3/8" is too thick, the Roomba won't be able to dock properly so be sure to get 1/4" thickness.  Also the 3/4" width is just about right, any wider and it will cover the sensors. 

The edges of the tape seem to start peeling off after lots of use.  I think I'm going to try to put some two sided tape on the ends of the section that I cut off so it wont' peel off so easily.

Monday, June 16, 2008

Applying individual timestamp migrations

I posted in my previous entry (Timestamp based migrations in Rails 2.1) about the new UTC timestamp based migrations in Rails 2.1. After working with them a little more, I found how to apply or remove individual migrations. Simply run rake db:migrate:up VERSION=YYYYMMDDHHMMSS to apply a single specific migration, or rake db:migrate:down VERSION=YYYYMMDDHHMMSS to remove a specific migration.

However, I found a bug with db:migrate:down as noted at http://rails.lighthouseapp.com/projects/8994/tickets/369-db-migrate-down-does-not-remove-migration-version-from-schema_migrations-table. When you run this, the self.down function of the migration is called and the database is changed. However, the entry in schema_migrations for this migration is not removed. So if you run rake db:migrate later, this migration will not be applied because Rails thinks that the migration has already been applied. My work around for this is to manually delete the row in schema_migrations after I run db:migrate:down.

Wednesday, June 11, 2008

Timestamp based migrations in Rails 2.1

One really cool feature added to Rails 2.1 is UTC timestamp based migrations. Now, when you generate a new migration, instead of the migration number being sequential, it's a UTC timestamp. That way if you're working on different branches of code, you don't need to coordinate between the braches who gets what version number.

But the best part of this is how the migrations are tracked. Instead of just keeping a current database schema number like before, Rails keeps track of each migration that has been run. Then when you run rake db:migrate, Rails only applies the migrations that haven't been run, they don't have to be in order.

As an example, say I added a migration two days ago called add_new_column with script/generate migration. 20080610012942_add_new_column.rb gets generated. My co-worker John is working off of another code branch, and yesterday he added a new migration called change_accounts. 20080610225643_change_accounts.rb gets generated. Then today I add a new migration called delete_state. 20080612020139_delete_state.rb gets generated. I have two migrations, and John only has his one. When I run rake db:migrate, my two migrations get applied, and when John runs it his one migration gets applied. When we sync our code branches, we get each others migration files. Even though John's migration was created AFTER the first one that I created, when he runs migrate, both of my migrations will get added, and his migration that was already added will not get run again. And when I run migrate, only John's migration will get added, even though it was generated before the last migration that I ran.

The way Rails does this is that the first time you run a migration with Rails 2.1, a new table gets created called schema_migrations. An entry is added to this table for each migration that gets run. The old schema_info table is deleted. That way any time you run a migration, it checks each migration file against the database to see if it's been applied to your database yet.

This feature is already proving very useful for me. I no longer have to have migrations completely syncronized between myself and the other developer working on my project. We each work on our own branch, and we merge our migrations together when we're ready to merge all of our code.

A good Railscast video showing this is up at http://railscasts.com/episodes/107.

New vacation pics on Flickr

Check out my Flickr page at http://www.flickr.com/photos/valenshek/. I just posted pictures, mapped ofcourse, from my recent vacation to Spain!

Wednesday, March 19, 2008

Dynamically changing img src doesn't always show new image with Internet Explorer 6

When you dynamically change the source of an image with Javascript, Internet Explorer 7 and Firefox will display the new image fine. But sometimes, I believe when the change was triggered from an event, the image won't display in Internet Explorer 6 after the change. A blank area will appear where the image should be (if you specify a width and a height for the image), and if you right click on the area and click Show Picture, the image will display. I really have no clue why IE6 behaves this way. I found a posting at http://blogmatrix.blogmatrix.com/:entry:blogmatrix-2006-10-15-0000/ that lists two solutions. A third solution, described in Comment #1, is the easiest solution though. Simply return false in the event that triggers the change. Example:

Say you have an onClick event in a link to change a different image on the page. Your code should be:

<a href="javascript:void(0)" onClick="changeImage(); return false;">Change Image</a>

The return false will make the image always display in IE6.

How to disable the image toolbar for images in Internet Explorer 6

By default, when viewing an image on a page with Internet Explorer 6, a little toolbar will appear in the upper left corner when you hold your mouse over the image for a few seconds. This toolbar really gets in the way if you want users viewing your page to do things with the image, like capture mouse clicks, drag the image, etc. Thanks to http://www.thesitewizard.com/webdesign/imagetoolbar.shtml, I found two ways to disable this. To disable the image for a whole page, add a meta tag to your header:
<meta http-equiv="imagetoolbar" content="no" />
Or to disable this on a per image basis, add:
galleryimg="no"
to the img tag.

Wednesday, March 12, 2008

Assigning custom data types to new columns during migration, part 2

In my previous article, Assigning custom data types to new columns during migrations, I showed how you can create columns with custom data types during a database migration. Simply specify :"data type", instead of :integer, :string, :binary, etc. An example would be :"smallint", since there is no direct way to create a MySQL smallint during a Rails migration.

However, I recently found that this doesn't always work. It works fine if you are creating a new table in your migration. But this does NOT work if you are adding or modifying a column in an already existing table, you get the error:
rake aborted!
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]

Has anyone else run in to this problem? It's annoying to have to construct SQL statements to add columns, after all that's what migrations are supposed to get rid of.

Friday, February 8, 2008

How to dynamically update the contents of one select list from selections in a different list

Rails support for making AJAX requests is great, it's very easy to make simple requests perform actions on the page in the background. A common scenario where you might want to use AJAX to make your pages more dynamic is to repopulate a select list in a form when the user modifies other elements on the form. The built in capabilities of Rails seem to have some problems dealing with select boxes where multiple items can be selected while doing these AJAX requests, however.

I will provide a simple case here where you have two select boxes - one is a list of vehicle types, and the other is a list of vehicles. Instead of having one huge list of all vehicles, you might want the list of vehicles to only show vehicles that are of the selected types. Using AJAX updaters form observers, you can dynamically update the vehicle list based on the type list being changed.

For this to happen, you need to place observe_field Rails helpers in your view for the page, to observe for changes to the field. Typically you can specify here what the URL of the action to call is, but observe_field has some trouble sending parameters for select boxes with multiple selections, so it will instead call a Javascript function. In the Javascript function (which isn't necessary if you aren't using a select multiple), you need to manually make create an Ajax.updater to update the "results" selection box items, creating the query string dynamically based on the selected types. Then you need an action in your controller to respond to the Ajax request, and a view for this action to fill in the correct values to the select box.

I created a simple example with a page where you can select what types of vehicles you want displayed (car, SUV, or truck), and whenever you change the type, the list of vehicles will be updated.

First, add two new actions to your controller. The first is the regular action to get the page for the first time, which I'll call show_list. Within this action, the list of types (from the constant TYPES) gets put into a variable for later loading. The second action, update_list, is what the AJAX request will call to update the vehicle list with selected types. Here is the code for the controller:
# these are just some constants.  Most likely you'll want to find things 
# in your database to return.
TYPES = {"car" => [["Honda Accord", "1"], ["Scion Tc", "2"],
["Ford Focus", "3"], ["BMW M6", "4"]],
"suv" => [["Jeep Wrangler", "5"], ["Ford Explorer", "6"],
["Toyota Highlander", "7"]],
"truck" => [["Ford F150", "8"], ["Dodge Ram", "9"]] }

# this is the action to get the page for the first time.  
def show_list
@types_all = [["Car", "car"], ["SUV", "suv"], ["Truck", "truck"]]
end

# this is the action that the AJAX request will call.  types[] will be
# specified in the parameters list, containing the different vehicle
# types that the user has selected.
def update_list
@vehicles_all = []
if params[:types]
params[:types].each do |t|
@vehicles_all = @vehicles_all.concat(TYPES[t])
end
end
# this part is really important, if you don't tell it not to render the 
# layout, the area where your selection box is will have the whole 
# controller's layout around it.
render :layout => false
end


Next, create a new rhtml file in your controller's view folder called show_list.rhtml. This is the initial page that gets loaded:
<% # this is a function I wrote in my application controller to load a
# Javascript file.  show_list.js must be loaded.
add_javascript_file("show_list", false) -%>

<% # I don't actually have anything to respond to this form, it's just to show
# select boxes.
form_tag({}, {:name => "show_list", :id => "show_list"}) do -%>

<p>Vehicle Types:
<%= select_tag "types[]", options_for_select(@types_all, []),
{:size => 3, :multiple => true, :id => "types[]"} %>
</p>
<% # the observe_field must call a function and not directly call a method
# on the controller.  Select form elements with multiple elements do not
# get correctly passed as parameters to the controller action, so we
# have to manually do it in a Javascript function.
# with any other type of field (including single selects), you can
# specify :url as a parameter and it will call that url.
# if :frequency is not present, a request will be made every time the
# selection is changed.  This isn't recommended, because the user may
# very quickly change selections.  0.5 ensures that a request is made
# at most every half second while the user is changing the selection.
-%>
<%= observe_field "types[]",
:function => "typeChanged('vehicle_list', $F('types[]'))",
:frequency => 0.5 %>

<% # the hourglass will show while the browser is waiting for a response
# from the server, to let the user know something is going on.
-%>
<div style="display:none; text-align:center;" id="hourglass">
<%= image_tag "ani-busy.gif", {:width => 32, :height => 32} %>
</div>

<p>Vehicles from selected types:
<% # the whole select tag must be in a div.  This is what will be updated.
# If the browser is Firefox, you can put the select tag ID as the area
# to update in the AJAX call, and return a list of options in your rhtml,
# but this will NOT work in Internet Explorer.
-%>
<div id="vehicle_list">
<%= select_tag "vehicles[]", "", {:size => 9, :multiple => true} %>
</div>
</p>

<% end -%>

Next, create another new rhtml file in your controller's view folder called update_list.rhtml. This is what gets sent to the specific div section that gets updated whenever the type selection list gets updated:
<% # render just the select tag here
-%>
<%= select_tag "vehicles[]", options_for_select(@vehicles_all, []),
{:size => 9, :multiple => true} %>

Finally, add a javascript function to a file that gets loaded with show_list.rhtml:
function typeChanged(areaToUpdate, typesToSend) {
// Manually create a request string with parameters
var queryStr = "/node/update_list";
var started = false;
if (typesToSend) {
for (var i = 0; i < typesToSend.length; i++) {
// the first type must have ? before it to start the parameters list.
// after that, it should be prepended with & to specify an additional
// parameter.
queryStr += (started ? "&" : "?") + "types[]=" + typesToSend[i];
started = true;
}
}

// before we send the request, show the hourglass.
$('hourglass').show();

// manually send an Ajax request to update the area passed in to the
// function.  Upon completion, hide the hourglass.  You can also specify
// functions to run for onError, onSuccess, and many others.
new Ajax.Updater(areaToUpdate, queryStr,
{onComplete: function() { $('hourglass').hide(); } });
}

This may seem like a lot to add for a simple page, but it's very easy to set all this up and work with much more complicated scenarios.

Thursday, February 7, 2008

Binding a Ruby TCPSocket to a local address and/or port

The Ruby TCPSocket class is a really easy to use class for making outbound connections and sending/receving data. But there's no way to bind to a local address or port for making the connection. The Socket class, which TCPSocket inherits from, has a bind call, but the constructor for TCPSocket immediately attempts to establish a connection using the default any port and any address. So it wouldn't do any good to bind on TCPSocket, since the connection is already made when you create it.

If you need to bind to a local address, you'll have to create a Socket object. The code below will bind to a port and address, and then attempt to connect. After that point, you can read from or write to the socket just like you can with TCPSocket. I'm not sure how to specify any address, or localhost, for in_addr. If anyone knows how to do that, please post here.

require 'socket'

# this is the address to bind to.  The first argument is the port, the second
# is the IP address (a string).  Pass 0 for the port to not bind to a specific
# port (the port will be auto assigned by the OS when a connection is made).
# The address MUST be an actual external address of the computer - 127.0.0.1 
# won't work.
in_addr = Socket.pack_sockaddr_in(12345, "10.10.1.3")

# for the outbound address, you must specify both a port and address
out_addr = Socket.pack_sockaddr_in(80, "www.google.com")

s = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
s.bind(in_addr)
s.connect(out_addr)

# from this point you can read from and write to using the standard Socket
# and IO methods.

s.close

Sunday, January 20, 2008

Picture of mine used on Schmap.com

A picture that I took in Montreal in August 2007 and posted on Flickr has been selected to be used by the online guide Schamp.com for their Montreal city guide! Check it out at
http://www.schmap.com/montreal/sights_historic/. Click Bonsecours Market, and cycle through the pictures on the right to find mine.

Tuesday, January 15, 2008

New version of Ruby In Steel without Visual Studio license

The folks at SapphireSteel Software have released a new version of Ruby In Steel, called Text Edition, that doesn't require you to already have a Visual Studio license, and it's only $49 at this time!

For those who don't know about it, Ruby In Steel is a full Ruby and Rails development platform for Windows with real time debugging (breakpoints, mousing over and typing variables to see their values), syntax error detection, color coding, indenting, and anything else that you'd want in a full featured IDE. Check my previous blog entry, Ruby In Steel, Ruby on Rails add on for Visual Studio, for a better description. Previously, Ruby In Steel was an add on for Microsoft Visual Studio, you already had to have a Visual Studio license for this to work.

This new version comes with a free version of Visual Studio 2008 that it uses behind the scenes, but you can only do Ruby and Rails development with it. They still sell the Visual Studio add on. The main differences are that the add on version has a faster debugger, and uses the Intellisense libraries that show possible values for objects and attempts to highlight incorrect syntax. If you already have Visual Studio, I'd still recommend the regular version, but if the price is too much the Text edition will still work great. The Intellisense in the full version still doesn't work too well with Rails code (but what can you expect since it's not strongly typed), but it does work pretty well for strict Ruby code. But if you don't have Visual Studio, the Text edition provides a very powerful full featured Ruby and Rails IDE for a great price, I would highly recommend it! You can get it at http://www.sapphiresteel.com/.

Wednesday, January 9, 2008

Exception_notification plugin for automated exception emailing

I found a really useful plugin called exception_notification that I've been using on my servers for several months now. It will send emails to addresses that you configure any time an exception is generated on your server, if the server is in production mode. The email contains the full details of the exception, including the call stack. It's almost as useful as the error page that gets displayed for exceptions in development mode.

The plugin has helped me discover and fix a whole bunch of obscure errors that I never would have discovered on my own or through users complaining.

This may not be appropriate for a server where you have a large volume of users. You probably wouldn't want to get thousands of emails of the exact same error a day especially if it's a bug that you already know about. But it works great for servers with a low volume of users, or for internal test servers. For a test server, your testers won't need to record the details of the error and send it to you separately, it will automatically be sent to you!

To get started, run
script/plugin install exception_notification

Then edit your config/environment.rb file to include the following line, specifying the email addresses to send exceptions to:
ExceptionNotifier.exception_recipients = %w(email_recipient_1@address.com email_recipient_2@address.com)

Another useful option you can add to environment.rb specifies who the sender of the exception should appear as:
ExceptionNotifier.sender_address = "\"App Error\" <apperror@domain.com>"

Then add this to your application controller if you want all actions in your application to generate exception emails.
class ApplicationController < ActionController::Base
include ExceptionNotifiable 

You can also include this only on the controllers that you want to generate exception emails.

The full source for this is at http://dev.rubyonrails.org/browser/plugins/exception_notification. Read the README file there for more detailed information on configuring it.