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.
Saturday, December 27, 2008
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:
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:
And it works!
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:
Then, for EVERY controller action where you are calling an ICE method, you must do something similar to this
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.
Labels:
roomba
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.
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.
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!
Subscribe to:
Posts (Atom)