Is JavaScript Overrated?

May 17th, 2007

Con-way graciously sent me to RailsConf, and even paid for the tutorials. I went to Thomas Fuchs’ morning tutorial “JavaScript Overrated? Or: How I Stopped Worrying and Put Prototype and script.aculo.us to Full” but I left after the first coffee break. Thomas is obviously a bright guy who’s done some great work with script.aculo.us, but his talk is pretty underpowered for a big room. A bit disappointing — lately I’ve been thinking that I haven’t given Javascript a fair shake. I could be convinced that Javascript is a dynamic OO scripting language that’s gotten a bad rap. Anyway, here are the high points:

Thomas assured us that lots of big companies use script.aculo.us and Prototype.

The Javascript libraries aren’t that big: the compressed version is 31K. And most everyone uses gzip compression on their web server, right? Uh, I don’t. Behind the times again.

I actually like that there is no script.aculo.us roadmap. “It’s done when it’s done.” It’s funny, I was going to make a joke about trying to implement that methodology at Con-way, but when I thought about it again, I wonder: don’t we do it that way anyway? We come up with big plans and schedules ahead of time, miss our targets, make excuses, and then … deliver it when it’s done.

Anyway, here’s script.aculo.us manifesto: Real-world. Small is beautiful. Ease development.

I don’t know why I hadn’t realized this before, but here’s the nut of how to do an AJAX request with prototype:
new Ajax.Request(‘/some_url’)
The server sends Javascript back and Prototype evaluates it.

Features in the new 1.5.1 release
– speediness
– CSS 3 selectors
– times() for String, padded strings
– use “return” instead of throw $continue
– Fix some Safari crashes
– JSON love

The official JSON library breaks Prototype.

Future features
– read/write attribute
– basic DOM builder
– wrap()
– curry(): like find. Huh? I should have paid more attention.
– defer()
– delay()

Another random observation — there are maybe 200 people in the room, and 95% have laptops. And most are MacBooks. My superficial impression is that the attendees are more stylishly dressed that they were at JavaOne.

There’s much more interesting conversation here at one of the tables outside the tutorial room (and free coffee). Someone’s “friend” is responsible for one of the largest Rails sites’ in the world: Paris Exposed. He handled a huge spike in traffic, and the only thing he need to do was switch to better session handling code. So when people tell you that Rails doesn’t scale, you can always say: “Well, what about parisexposed.com?”

Now the table has been highjacked a Microsoft IronRuby evangelist. He’s really worried that people will ignore Microsoft’s cool Ruby VM because we all ‘hate’ Microsoft. I am not sure that anyone here ‘hates’ M$, but this guys’ style is just wrong for us. It feels like he stumbled upon the wrong conference. Though it is cool to see a 17″ PowerBook with Microsoft corporate asset ID.

Rails PDF Plugin Error Pages

February 8th, 2007

I needed to generate PDFs for the OBRA website, so I installed the Rails PDF plugin and Ruby PDF::Writer.

I’m happy with both. Typical for Ruby and Rails, they “just work” and my code is terse and expressive. (Well, the Rails plugin source code is a bit rough, and there are no unit tests. And the PDF::Writer API is a bit of a head-scratcher, but I blame Adobe for that.)

One minor annoyance is that Rails returns PDF page (.rpdf) errors as “application/pdf” content with names like mypage.pdf.html. Safari, at least, just saves the page to the desktop.

I improved this by overriding a couple methods in my ActionController:

def rescue_action_in_public(exception)
  headers.delete("Content-Disposition")
  super
end

def rescue_action_locally(exception)
  headers.delete("Content-Disposition")
  super
end

And now I get my errors in the browser, where I like them.

Old Wine, New Bottles

January 17th, 2007

Ten years later, I get around to updating this site’s design and used something other than static HTML.

Ruby on Rails as Mailman External Archiver

January 23rd, 2006

I set up a Mailman mailing list. I want archives. I want these archives to look like other dynamic parts of the site (brought to you by Ruby on Rails). And I want to integrate a couple years’ worth of Topica messages.

At I first, I figured I’d use MHonArc or something similar. Mailman’s external interface is lightly documented, but simple and capable once you figure it out. Looking at the Python code helps in /usr/mailman/Mailman.

I decided to use Rails in the end. Maybe not the best choice, but I like keeping all my UI code in once place as much as possible.

I have an ActionMailer subclass with a delivery method:

class MailingListMailer < ActionMailer::Base
  def receive(email)
    post = Post.new()
    post.subject = email.subject
    post.body = email.body
    post.sender = email.friendly_from
    post.date = email.date
    post.save!
  end
end

class Post << ActionRecord::Base ....

I added an entry to PUBLIC_EXTERNAL_ARCHIVER in Mailman's mm_cfg.py file. On Suse 10, it's in /usr/lib/mailman/Mailman. I've add backslash line breaks for legibility here.
PUBLIC_EXTERNAL_ARCHIVER = '/srv/www/rails/obra/current/script/runner \
-e "production" "MailingListMailer.receive(STDIN.read)" \
>> /srv/www/rails/obra/shared/log/production.log'

I made several mistakes:

  • You need to restart Mailman for it to pickup your changes: /usr/lib/mailman/bin/mailmanctl restart
  • The apostrophes need to be around your command: '/srv/www ... production.log' Otherwise, you are trying to execute Python code, not assign a string variable.
  • Leave out -e "production" and Rails will execute in its development environment.
  • Ensure your logs are writeable by the mailman user, or nothing will work very well.

A typical Mailman error message in /var/lib/mailman/logs/error is "external archiver non-zero exit status: 127." Not very helpful. My shell foo isn't up to the task of redirecting standard error and standard out from the PUBLIC_EXTERNAL_ARCHIVER command. I got better info with Mailman calling a Bash script that then called the Rails runner. I validated that things worked at each small step, and I had to take baby steps because I kept putting a single quote where I needed a double quote, etc.:

  • Unit test for the ActionMailer
  • Run the ActionMailer in irb
  • Run the runner: sudo -u mailman /srv/www/rails/obra/current/script/runner -e "production" "MailingListMailer.receive(STDIN.read)"
  • Write a shell script to call the runner

Of course, it's helpful the public Mailman pages point to my new Rails-based archive. Here's how I do it. In Mailman/mm_cfg.py:
PUBLIC_ARCHIVE_URL = 'http://%(hostname)s/mailing_lists/%(listname)s/posts'

I like the end result, and it's easy to do once you know how to do it. Next step is to see if Rails can sew a header and footer onto the Mailman list info pages. I am keeping the gnu, of course.

Ruby, Rails, and FXRuby on OS X Tiger

January 12th, 2006

I needed to install Rails and FXRuby on a couple of my Mac OS X boxes. They are all running Tiger (10.3). I used the Apple development tools that come on the install CD. (I did try the latest dev tools from Apple’s site. I had some problems — probably solvable problems — but the older dev tools were just fine for me, so I rolled back.)

Before you dive into this, ask: do I really want to do this all “by hand?” There are alternatives that install and configure Rails and other Unix software for you. Consider the excellent Locomotive package. DarwinPorts is another good option, although the Fox Ruby packages were an older version (1.2) last time I checked. Finally, there is Fink. Fink is similar to DarwinPorts, although there doesn’t seem to be as much RUby interest there.

Ezra Zygmuntowicz has the best instructions for Rails on OS X that I’ve found. Building Ruby, Rails, LightTPD, and MySQL on Tiger is also helpful. Rather than repeat these instructions, I just added some notes from my experience.

Ruby

OS X comes with ruby installed in /usr/bin. This version doesn’t work so well with the Ruby MySQL bindings and readline. It’s easy to replace with a new copy straight from the source.

You want to make sure OS X will use your version of Ruby. And unless you want to muck around with add “–prefix=” to everything you compile, add a couple lines to your PATH in your ~/.bash_login file:
export PATH="/usr/local/bin:/usr/local/sbin:$PATH"

At least for me, curl needed the ‘–location-trusted option’ to download files from Ruby Forge:
curl --location-trusted -O http://rubyforge.org/frs/download.php/2338/ruby-1.8.2.tar.gz

The SSL patch to Ruby 1.8.2 gave me the following compilation error, so I didn’t use it:
ossl_x509store.c:541: error: 'struct x509_store_ctx_st' has no member named 'param'

It’s entirely possible this patch is very important, but I’m not doing anything with Ruby and SSL right now.

Without the SSL patch, there was a new error:
readline.c:780: error: 'rl_event_hook' undeclared (first use in this function)

So I installed a new (GNU!) version of readline:
curl -v -O http://ftp.gnu.org/pub/gnu/readline/readline-5.1.tar.gz
tar zxvf readline-5.1.tar.gz

GNU readline built and installed without any problems, and then Ruby built fine as well.

MySQL

Like many many other people, I had some problems building the Ruby MySQL bindings. The following worked for me.

Download MySQL 4.1

Add “/usr/local/mysql/bin” to your PATH in .bash_login.

Download MySQL bindings directly, not as a gem

ruby extconf.rb --with-mysql-config

Fox

Sure you don’t want to use DarwinPorts? OK.

Fox requires several image libraries you probably don’t have installed already. I grabbed the versions from the Fox download page and they build and installed with minor tweaks.

The TIFF lib needs a newer version of config files and LZW:
cd tiff-v3.5.7/
cp /usr/share/libtool/config.guess .
cp /usr/share/libtool/config.sub .
cp libtiff-lzw-compression-kit-1.3/tif_lzw.c tiff-v3.5.7/libtiff/

Fox itself:
./configure --enable-shared --enable-static --prefix=/usr --with-opengl=no --x-includes=/usr/X11R6/include

Test from the Terminal:adie

FXRuby

There’s a gem, but I used the source instead.
ruby install.rb config -- --with-fox-include=/usr/include/fox14 --with-fox-lib=/usr/lib/fox14
ruby install.rb setup
sudo ruby install.rb install
irb
require 'fox14'

As a side note, I later enabled font anti-aliasing with XFT using “–with-xft” when I built Fox. But I needed to install several dependencies via DarwinPorts before I could get it to work

gears