Rails 2.2 has been released

The much anticipated Rails 2.2 release is finalized with a host of new features. One of the features we are most excited about are the new multi-threaded capabilities for Rails. This will improve application response time in general, and allow us to get more use out of each server. I think memoization can be useful as well, it will be interesting to see how much it helps. As usual, Peter Cooper at Ruby Inside has put together an all-encompassing post with all the info you might need. And as a side note, this release also includes a little patch submitted by our team.

Thanks and congratulations to the core team for another solid release.

Posted by Adeh Thu, 27 Nov 2008 19:06:00 GMT


mongrel --prefix does not properly notify rails 2.1.1

As of Rails 2.1.1, ActionController::AbstractRequest.relative_url_root no longer exists. It has been replaced by ActionController::Base.relative_url_root. This allows you to run your rails app in a virtual sub-directory of your webserver. The mongrel rails handler uses this method to set the relative url for your rails app. When working properly, mongrel_rails start --prefix /app would result in rails automatically generating URLs like http://somedomain/app/action.

Currently in mongrel 1.1.5 and Rails 2.1.1, if you wish to have this functionality you must set the relative_url_root by hand somewhere in your environment like so:
ActionController::Base.relative_url_root = "/app" if 'production' == ENV['RAILS_ENV'] 
I have submitted a patch to mongrel, but if you can’t wait for the new release of mongrel, here is the patch:
Index: lib/mongrel/rails.rb
===================================================================
--- lib/mongrel/rails.rb        (revision 1036)
+++ lib/mongrel/rails.rb        (working copy)
@@ -147,9 +147,15 @@
         require env_location
         require 'dispatcher'
         require 'mongrel/rails'
-
-        ActionController::AbstractRequest.relative_url_root = ops[:prefix] if ops[:prefix]
-
+        
+        if ops[:prefix] 
+          if ActionController::Base.respond_to?('relative_url_root=')
+            ActionController::Base.relative_url_root = ops[:prefix] # new way to set the relative URL in Rails 2.1.1
+          else
+            ActionController::AbstractRequest.relative_url_root = ops[:prefix] 
+          end
+        end
+        
         @rails_handler = RailsHandler.new(ops[:docroot], ops[:mime])
       end

Posted by Adeh Thu, 09 Oct 2008 19:52:00 GMT


freezing git Rails into your SVN project

While all the cool kids are switching to git (notably Rails itself), we still have several projects that live in svn repositories and we really have no desire to migrate them. We do, however, want to upgrade to the latest Rails version, now managed via git at github.com.

While I have found lots of old tutorials based on svn, or new ones explaining how to freeze rails to your git-based project, I have not seen a good one about freezing git-based rails to an svn-based project. Here are the steps I used:

First, remove your older svn-frozen copy of Rails
$ svn rm vendor/rails
$ svn ci -m 'upgrading rails to the latest git stable version *** this revision is missing rails ***'
Next, get your own local Rails repository
$ cd vendor
$ git clone git://github.com/rails/rails.git
$ cd rails
Now you can add the new version of Rails to your svn project
$ git checkout -b v2.1.1
$ svn add ../rails
$ svn revert --recursive .git
$ cd ../.. # back to your root dir
$ rake rails:update # update the supplemental rails files
$ svn ci -m 'upgrade to rails 2.1.1'

Of course, you can replace 2.1.1 with whatever the current version you are interested in. Later on, when a new version of Rails is released, you can simply update your git repo and switch to a new branch like so:

$ cd vendor/rails
$ git pull origin master
$ git checkout -b v2.2.0
$ svn status
# here you would have to add any deleted files, and add any new files
# this step could easily be automated
$ svn ci -m 'enjoy the latest Rails'

Note: If you are upgrading from 1.2.x -> 2.x.x make sure to add back the plugins that you were using such as will_paginate or acts_as_tree.

$ script/plugin install git://github.com/rails/acts_as_tree.git
$ svn add vendor/plugins/acts_as_tree
$ script/plugin install git://github.com/mislav/will_paginate
$ svn add vendor/plugins/will_paginate

Hope this helps anyone else trying to do the same thing. I am sure there are other ways to accomplish a this task as well. Feel free to put your solution in the comments.

Posted by Adeh Fri, 19 Sep 2008 16:51:00 GMT


installing mysql gem on MacOS X Leopard

Using Rails 2.1.1, I get this warning about the mysql libraries associated with Rails:

The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql.

As many have noted, the suggestion of `gem install mysql` doesn't seem to work well on the vanilla Leopard install with the standard MySQL pre-compiled binary. I followed lots of good advice from wonko, jlaine, hivelogic, and Seth Willits, but finally none of it worked.

Using the command from wonko:

sudo env ARCHFLAGS="-arch i386" gem install mysql -- \
  --with-mysql-dir=/usr/local/mysql --with-mysql-lib=/usr/local/mysql/lib \
  --with-mysql-include=/usr/local/mysql/include

got me the ulong compile error mentioned by jlaine,. Unfortunately, jlaine's instructions didn't work for me, the manual install step doesn't seem to really install anything. I realized I had to take it step further by modifying the source of he gem itself.

In order to fix the compile error in mysql.c, it helps to understand how the gem install command works. First, gem goes online to find the correct file, then downloads the packaged .gem file to your local gem cache. Then, gem unpacks the .gem and runs extconf.rb and make/make install. From reading extconf.rb, one can see that the mysql gem uses a file called mysql.c.in as a template to build a properly configured mysql.c, which then gets compiled into the C library that we will use.

$cd /Library/Ruby/Gems/1.8/cache
$sudo gem unpack mysql-2.7.gem
$cd mysql-2.7

This gives you the source of the gem. Open mysql.c.in to add the single line we need.

#define ulong unsigned long // quick fix so that it compiles on my machine

Then we need to repack the gem, copy it to the cache folder, and install our customized version using the command above.

$sudo gem build mysql.gemspec
$sudo mv mysql-2.7.gem ../mysql-2.7-CUSTOM.gem
$sudo env ARCHFLAGS="-arch i386" gem install mysql-2.7-CUSTOM.gem -- \
  --with-mysql-dir=/usr/local/mysql --with-mysql-lib=/usr/local/mysql/lib \
  --with-mysql-include=/usr/local/mysql/include

All this for one line of code...but finally:

$ gem list mysql

*** LOCAL GEMS ***

mysql (2.7)

Thankfully, most of the time we don't need to go through all this just to instal a library. This sort of thing happens rarely. But its great to know that as long as you have your command line, a good compiler, and some detective skills, you can fix many problems on your own!

Posted by Adeh Fri, 12 Sep 2008 21:07:00 GMT


railscasts to help you become a ruby ninja

click here to read the Chinese vesion of this article
点击这里浏览本篇文章的中文版

As the popularity of Rails grows, the number of resources available to learn Rails also grows. One of the best methods that has come about is the use of Screencasts. Screencasts are movies that show the code as you listen to the presenter explain the concepts. Often, they go over material that can be found in books. But presented in this way, it might sink in a little better as you use 2 of your senses to absorb the material.

First, there is a set of excellent FREE screencasts from Ryan Bates at http://railscasts.com. These are short and to the point, often highlighting a new feature. You can have them download to your computer automatically through iTunes (except in China where Feedburner is blocked), or you can download them directly from the website. There is a set dedicated to the new features of Rails 2.1 that deserves to be checked out.

Second, the father of screencasts, @topfunky a.k.a Geoffrey Grosenbach has put together a great set of training materials at peepcode.com. They are not free, but quite affordable at $9 per cast. They are well done, informative, and full of great examples. We have used them to get up to speed on new versions of Rails, and downloaded some of the PDF books. I highly recommend these materials to get more familiar with Rails.

Rails runs on Ruby, and I have found a good set of screencasts that goes into how to program with Ruby. Dave Thomas of The Pragmatic Programmers (author of Agile Web Development with Rails) goes through the basics of the Ruby object model, class inheritance, and meta-programming. This will help you take advantage of the power inherent in Ruby and give you the foundation to understand the Rails framework. These screencasts are $5 each.

If you are interested in Rails and Ruby, I highly recommend using the resources available on the web. Of course you will need to download the tools and start coding yourself as well!

Happy Hacking!

Posted by Adeh Mon, 16 Jun 2008 18:47:00 GMT


Rake task to help manage svn rename

I recently had to rename several views+controllers in a project. This is a very wearisome task since its not just a directory or a file; but directories, files, tests, fixtures, and other files that get generated by the Rails generator helpers. I searched for a little piece of code to help manage this, but didn't find anything. That may be due to the fact that earlier versions of rake did not work with arguments very well. Here is my little rake task, you can put it into a file in your lib/tasks directory and run it using:
$rake svn:rename[old_name,new_name] # notice no spaces
And here is the code:
namespace :svn do
  FILES_TO_RENAME = [ "app/views/%s",
                      "app/controllers/%s_controller.rb", 
                      "app/models/%s.rb", 
                      "test/unit/%s_test.rb", 
                      "test/functional/%s_controller_test.rb", 
                      "test/fixtures/%s.yml"]
  task :rename, :from, :to do |t, args|
    FILES_TO_RENAME.each do |s|
      from_f = s % args.from
      to_f = s % args.to
      if File.exists?(File.expand_path(from_f))
        puts "Renaming #{from_f} -> #{to_f}"
        puts %x[svn mv #{from_f} #{to_f}]
      else
        puts "Skipping #{from_f}. File not found."
      end  
    end
  end
  
end
Please leave comments if you see a way to improve this. Feel free to modify it to your needs and tell me about it.

Posted by Adeh Fri, 13 Jun 2008 21:48:00 GMT


Rubob (Ruby Object Browser) 0.0.3 released

After literally a year of not finding time for finishing touches, I decided to finally just release what I have. It works fine, after all.

Rubob is based on a little tool I wrote together with Matthias Hopf in 1997 or so to play with the Java Reflection API. When I started working with Ruby almost a decade later, I realized how much easier it would be in Ruby, so I rewrote it. And then it sat there...

So what does it do?

Rubob generates a hyperlinked Web-view of your program while it runs. It can very easily be added to any existing application (one line of code).

With Rubob, every object in the system has a corresponding URL. When you access that URL, Rubob generates a Web page that contains a human readable version of the object. All instance variables are hyperlinked to the URL for their value; so you can click your way through from object to object to explore the state of your program while it's running.

Certain classes, such as Array and Hash, have a custom representation that makes their content easier to explore.

You can add your own custom representation of objects using a simple API that I'll explain when I have some time.

Here is the code.

Enjoy!

Posted by Uli Tue, 29 Apr 2008 21:49:00 GMT


RadRails 1.0 released!

When we first started developing in Rails, back in early 2006, we all used RadRails, and loved it. However, as the original developers moved on to other things, RadRails stopped improving. Finally we have all switched to Textmate, an editor available only on MacOS X.

With the release of RadRails 1.0, the original Rails IDE comes back onto the scene with a bang. Integrated debugging, svn support, javascript syntax highlighting… this thing has it all. One of the things I missed most about RadRails was the tight SVN integration. What I disliked was having so many panes open that didn’t really help me be more productive, and having to use the mouse to navigate between files. Textmate has really shown me how nice it can be to just have your code filling up the screen. I also love to move between files by filename, not having to touch the mouse, and being able design custom commands for custom key-combinations.

I downloaded the newest RadRails to see if my old beloved IDE could hold its own against my sleek new editor.

The new Aptana version of RadRails is really nice; easy to install and get started with. All the old functionality that I remember is still there, and now it seems visual debugging works as well. However, to me now it seems so slow and over-engineered. After switching to Textmate, I never missed the extra panes, and use the terminal for any non code editing tasks. With the multitude of plugins, services, panels and an entire Java application server powering it, RadRails can’t match the responsiveness of a pure editor like Textmate, even on my Macbook Pro 1.83.

So although I personally don’t feel the need to switch back, I can still heartily recommend RadRails as a development environment for anyone wanting to do Rails development. On Windows, the only strong competitor is NetBeans (which caught up while RadRails was in hiatus). And since it is free, there is no penalty to give it a try. 

 

Congrats to the current team and to the creators of RadRails!

 

Posted by Adeh Mon, 17 Mar 2008 21:47:00 GMT


Javascript Filter on table, ol, ul...

It’s very common to enter a keyword and then filter it in a table or list. The easiest way could be go through each item of the table or list and then compare the keyword with the inner html of that item. But there is a drawback of this method. For instance, how to do filter in a table which has rows whose rowspan are set to bigger than 1? The code will break the layout of that table completely.

The method will come out with is to add a matching keyword to every item that are filterable. In other words, instead of comparing with the inner html, the code do it with the matching keyword. This gives the filter more flexibility. We will discuss the code a little bit belows. Note that it’s built on Prototype and used in Ruby on Rails. So, we have helper function to generate javascript in view too. But here, we just talk about the pure javascript part.

Here is an EXAMPLE

function strip_spaces(stripee) {  
    return stripee.replace(/(^[ ]*) | ([ ]*$)/g,'');
}

function filter(id, criteria) {
    var t = $(id);
    if (!t) { return; }

    t.getElementsByClassName('no_matched_notice').each(function(elem) {
        elem.remove();
    });

    var notice_msg = 'No matching data found!';
    criteria = strip_spaces(criteria);

    empty_input = criteria.length === 0;

    var matched_none = true;
    t.childElements().each(function(elem) {
        // if the user doesn't input anything, then show all the elements
        if (!elem.matched_strs || empty_input) {
            Element.show(elem);
        } else {
        // else find the element
            matched = false;

            elem.matched_strs.each(function(str) {            
                if (str.toUpperCase().indexOf(criteria.toUpperCase()) != -1) {
                    matched = true;
                    matched_none = false;
                    return;
                }
            });

            matched ? Element.show(elem) : Element.hide(elem);
        }
    });

    if (matched_none && !empty_input) {
        var tag = t.tagName;
        var ins = null;
        switch (tag) {
            case "TBODY":
            case "TABLE":
                ins = new Insertion.Bottom(t, "<tr class=\"no_matched_notice\"><td colspan='100'>" + notice_msg + "</td></tr>");
                break;
            case "OL":
            case "UL":
                ins = new Insertion.Bottom(t, "<li class=\"no_matched_notice\">" + notice_msg + "</li>");
                break;
            default:
                ins = new Insertion.Bottom(t, "<" + tag + " class=\"no_matched_notice\">" + notice_msg + "</" + tag + ">");
                break;
        }
    }
}

In html, all we need to do are:

1) add an array of keyword to each item which is filterable
$('tr_01').matched_strs = ["apple", "banana", "pineapple", ..., "pear"])
$('tr_02').matched_strs = ["bamboo", "eggplant", "cabbage", ..., "pepper"])
...
$('tr_02').matched_strs = ["elephant", "tiger", "monkey", ..., "fish"])
2) add a text field to enter keyword:
<input id="keyword" type="text" />
3) bind filter function to keyword’s event:
$('keyword').onkeyup = function() {filter('food', this.value);};
$('keyword').onchange = function() {filter('food', this.value);};

That’s it! :)

Posted by Shaokun Tue, 04 Dec 2007 15:27:00 GMT


Textmate script to restart mongrel

I often find myself needing to restart the rails app I am working on while in Textmate. Sure, its easy enough to switch to a terminal window and hit up-arrow, but since Textmate is a wonderfully developer friendly app, I decided to see what I could do about automating a common task.

In Textmate go to Bundles -> Bundle Editor -> Edit Commands

Use the + at the bottom to create a new Command

This gives you a blank template for a new command. The command editor gives you control over several aspects of your current working document and project. Since this is an app restart for development purposes, I choose to save all files before executing the command. Then, I just put in a few shell commands that will be executed directly. I like to do a clean restart so that the same script works even if this is the first time starting it up:

echo "Restarting the App..." 
cd "$TM_PROJECT_DIRECTORY" 
mongrel_rails stop
mongrel_rails start -d -p4040

This command takes no input, and puts the output into a tooltip. Finally, I need to select a key combination. cmd-R is taken, so I settled on cmd-G (for GO!).

That’s it. My very own custom command in Textmate in under 5 min. I leave the “Stop App” command as an exercise for the user.

Posted by Adeh Mon, 03 Dec 2007 22:40:00 GMT