Year: 2006

Getting Real by 37signals

I recently read ‘Getting Real‘, a book (only available as pdf) by 37 signals. 37 signals are the people behind the much hyped Ruby on Rails and a bunch of webapps based on this RoR (=Ruby on Rails) framework.

Why I wanted to read this book
I use RoR with success for an ongoing project at my daytime job and also used it for an ‘after-hours’ sideproject of which at least the development was a success thanks to Rails. I’ve also used Ruby (it works without Rails too) for more little projects and ‘glue’ than I can count.
Seeing that Getting Real is almost as hyped as RoR itself I figured I’d shell out the $19 and check what Getting Real is all about. After all, Rails has turned out to be a very productive and really quite fun web development framework. (but then, after years of doing VC++/MFC development even a lobotomy would seem ‘fun’… or even cobol… nah… just kidding about the cobol)
Continue reading

Fixing a rake schema.rb oracle dump

El Problemo
When issuing a ‘rake db:schema:dump’ (or a simple ‘rake test’ since it uses db:schema:dump) on the legacy oracle db mentioned in the previous post the schema.rb contained some weird entries like:

t.column "timestamp", :datetime, :default => #<date : 4903089/2,0,2299161>, :null => false

The culprits were basically field defaults (like the above, using ‘sysdate’ as default) that aren’t handled properly (not even sure if they should). Since this is a legacy db accessed by tons of mainly C/C++ code on which I’m tacking a web ui, changing this to something that suits Rails is usually not possible.

Any other rake tasks using the schema.rb stumbled over these entries so I was basically unable to do a simple ‘rake test’.

Unfortunately I only found the occasional mention of this issue but not a real solution (yet).

El (hack’n’slash) Solution
Basically all I needed db:schema:dump to work correctly for was being able to run tests. For a variety of accidental reasons I choose to run these tests on a mysql db on a w2k box. (at work I’m using xwin under cygwin on a wxp installation to connect to a CentOS server for my rails development… so this might not seem a logical decision… but explaining the reason behind choosing mysql to run the tests is really totally out of scope of this post)

Easiest solution was to filter the badies (renegades and outlaws) out of schema.rb before it was used for something else.

I made an extra db:schema:clean task to read/filter/write schema.rb, called it from db:schema:dump and put these in a file called ‘databases.rake’ in my Rails lib/tasks folder.

databases.rake:

namespace :db do
namespace :schema do
desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
task :dump => :environment do
require 'active_record/schema_dumper'
File.open(ENV['SCHEMA'] || "db/schema.rb", "w") do |file|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
Rake::Task["db:schema:clean"].invoke
end
desc "Fix the sysdate timestamps from an oracle schema.rb"
task :clean => :environment do
File.open(ENV['SCHEMA'] || "db/schema.rb", 'r+') do |f|
lines = f.readlines
lines.each do |it|
it.gsub!(/:default => #<date : 4903089\/2,0,2299161>,/, '')
it.gsub!(/:default => "EMPTY_BLOB\(\)",/, '')
end
f.pos = 0
f.print lines
f.truncate(f.pos)
end
end
end
end

(blame WordPress for losing indentation… at least I do!)

Ok… probably really basic stuff for the harcore Railsers out there, but I hope this will help some ‘nuby’ Railsers save some time hunting for where/what/how with this great framework.

(2nd post today, I’ve got another one up my sleeve but will stop now before someone asks me to take a ‘doping test’)

Rails models with attributes that shouldn’t be updated

Situation
A Ruby on Rails project I’m working on during my day-time job (as if I have a night-time one) has a couple of tables with fields that are changed by external processes. (note: it’s a legacy oracle database that’s had some slight mods where possible to make it more Rails-y). The bulk of fields in these tables however contain data that can be changed using a Rails interface I’ve build. These not to be updated fields need to be initialized when writing a new record and should be read (to be displayed) as normal fields.

So what’s the problem then?
Normally you’d just issue an update to only modify the needed fields, but at the moment ActiveRecord can only alter records by doing a read followed by an update of all fields (please correct me if I’m wrong).

This poses the problem that some fields might be changed by an external process after the read and before the write, resulting in ActiveRecord writing the old data back to the table. (resulting in a whole bunch of unwanted, very evil things of which I really don’t even want to think about fixing)

Solution
I found a workaround by overriding update_attributes in my model as
follows:


def update_attributes(attributes)
@attributes.delete('fieldthatshouldnotbechanged1')
@attributes.delete('fieldthatshouldnotbechanged2')
@attributes.delete('fieldthatshouldnotbechanged3')
super(attributes)
end

This effectively deletes the fields from the hash that’s used to construct the update statement. You’ll see in your development.log that the issued update statement doesn’t contain the deleted fields anymore.

I only tried it with update_attributes since that’s what I used to update the fields.

I hope this doesn’t cause any unwanted issues, but if it does I’ll post about it here.

Switch between Rails controller and view in Komodo

Yesterday I tried radrails, which is quite nice for a free tool. Being a Komodo fan however (thanks to my employer for paying the license) the only obvious advantage for me would be being able to switch between controller and corresponding view.

Because I was getting a bit jealous of this feature in Textmate/RadRails/… I cooked up a way to do the same in Komodo.

How can this work in Komodo ?
When calling external commands (via the Toolbox) in Komodo you can give path + linenumber of current file being edited (amongst others) as parameters. You can start the Komodo binary passing a filename + linenumber, and Komodo is nice enough not to start itself twice or load the same file twice when doing this.
The ‘figuring out what controller/action we’re in and calling the corresponding view‘-part (and vice versa) is handled by a little ruby script. (which could probably be much tighter, but I’m still a ‘ruby nuby’ and if I have to clean it up before publishing it’ll probably never leave my personal Toolbox… so be thankfull I have enough guts and ego to dare publish my dirty code 😉

How to install this script in the Komodo toolbox ?

  • Save the script below (let’s call it ‘open_ctrl_view.rb’) wherever you like to save such things.
    Remember to chmod +x it to make it executable!
  • In open_ctrl_view.rb : Edit the path to your komodo installation, or just put ‘komodo’ if komodo is in your search path.
    Edit the shebang to point to the correct ruby version if necessary.
  • In komodo: add new command in toolbox. As command, enter ‘open_ctrl_view.rb %F %L’ (include full path to whre you saved open_ctrl_view.rb if necessary)
    %F will insert the full path and %L the current line of the file being edited
  • Run in: ‘Command Output Tab’ (default option) and I marked ‘Do not open output pane’ below. If necessary you can always switch to the output pane manually if something went wrong.

Add key binding if necessary (warning: this is a bit buggy in Komodo 3.5.2 but should be fixed in 3.5.3)

Windows users: Probably the same as above, except no need for chmod’ing, and you’ll probably need ‘ruby open_ctrl_view.rb %F %L’ instead as command.
Mac users: Aren’t you using Textmate ?

The script (open_ctrl_view.rb)
No guarantees are made. Your head might explode, ladadi ladada, etc.
I was going to include it as text in this post, but even enclosed in the proper tags it looks all funny, so download it here.

Closing comments…
If you make nice enhancements: let me know! (what about a similar script that loads the model your cursor is positioned on ? Komodo can also send the word your cursor is on as a parameter)

Conditional partials in Ruby on Rails

Have you ever wanted to include a partial in Ruby on Rails only if the partial file actually exists ? This can be handy e.g. if you want to be able to include a special menu (as a partial) for some controller actions based on the action name (controller.action_name) but don’t want to make a dummy partial for every action (which is normally needed since Rails will throw an error if it can’t find a partial).

The following example will render a partial contained in the file _.rhtml only if this file exists:

def render_menupartial
render_partial(controller.action_name) if FileTest.exist?(File.join(RAILS_ROOT, 'app', 'views',controller.controller_name,'_'+controller.action_name+'.rhtml'))
end

remember to call this from your view (or probably layout) like < %= render_menupartial %> instead of < % render_menupartial %>.

I know: basic stuff, but since I already used this basic functionality quite often I’m sure someone out there will find this useful.

Paging file error after copy W2K partition

After copying a Windows 2000 installation (differend disk/partition, same machine) you get the following error:

Your system has no paging file, or the paging file is too small.

Followed by instructions on how to change the paging file settings.

Unfortunately, after you clicked ‘OK’ and are waiting for the desktop to appear, you get the login screen again and are thus unable to login to your Windows installation.

Googling finds the following page: http://support.microsoft.com/kb/249321/.
This page mentions a number of possible solutions, none of which seem to be really feasible:

If however you have another partition that still works on the same machine (probably the source partition you copied) and you can access the ‘new’ installation partition from this one, you can try the following much easier solution:

  • Boot Windows using the working partition
  • Start Regedt32
  • Choose HKEY_LOCAL_MACHINE
  • Choose ‘File/Load Hive’ from the menu
  • Open on the new, faulty partition Windows\System32\Config\Software and give it a name (e.g. tmp) when asked
  • Perform the change as mentioned under 3. at http://support.microsoft.com/kb/249321/ in this ‘tmp’ hive
  • Choose ‘File/Unload Hive’ to save your changes

Try to reboot your new installation again. Hopefully it will work for you. At least it did for me.
Now, follow the instruction in http://support.microsoft.com/kb/q223188/ to restore the correct drive assignment.

Apache – adding local virtual domains

Why ?
Because it’s nicer, handier and sometimes just plain necessary to refer to ‘test-sites’ on your development machine as http://project instead of http://localhost/project. (first time I needed it was when breaking my head over mod_rewrite)

I’m still running a Fedore Core 3 Linux installation here, but I guess this will be the same on 90% of standard Linux installations.

How ?
Add the fake domain to /etc/hosts, so your computer knows the ip addres (=local) and doesn’t need to query dns (which won’t work).
Also change apache httpd.conf to add the domain and the corresponding ‘root path’.

Add the domain to /etc/hosts
Add the domain to your /etc/hosts file, either as a new domain pointing to your local ip (127.0.0.1), or as an alias to your machine’s entry that’s already in there. Look for the following line (there’s probably only one in there):

127.0.0.1 localhost.localdomain localhost

Now add your ‘test’ domain, let’s call this one ‘project’:

127.0.0.1 localhost.localdomain localhost project

Now ‘ping project’ and you’ll see the ping going to 127.0.0.1. NO REBOOT NEEDED (only a save ofcourse), this isn’t windows!

Change Apache httpd.conf
Next, we need to add the virtual domain to apache’s config file, which is located at /etc/httpd/conf/httpd.conf (on FC3, otherwise ‘find’ it). At the end of httpd.conf, add the following (let’s pretend the root of our domain is located at /var/www/html/project on the filesystem):

<virtualhost *:80>
DocumentRoot /var/www/html/project
ServerName project
</virtualhost>

Use ‘service httpd restart’ to restart Apache with the new config. (if this doesn’t work, try ‘httpd -k restart’)
Open a browser, surf to’ http://project’ => bingo!

Running Windows ?
I haven’t tested this, but I guess instead of adding your domain to /etc/hosts, you’ll need to find a file called ‘lmhosts’ (no extension!) and add your domain pointing to 127.0.0.1 there. I *think* the apache httpd.conf modification will be the same.