RudyGems

Matthew Rudy Jacobs
see me swim
Github
see some of my code
WorkingWithRails
see me working with rails

Stop adding methods to Symbol just to make your DSL look pretty!

I remember the first time I saw Datamapper.

I liked saying “:something.gt something_else”.

It was pretty.

But after a while I realised it wasn’t necessary.

So why are we still building APIs that involve extending Symbol?

I saw this on an extension called Plucky for MongoMapper

Comments (View)

Ruby Enterprise Edition still faster than Ruby 1.9.2?

With Ruby 1.9.2 due to ship on July 31st, I thought I’d take Ruby 1.9.2 preview 3 for a spin.

A quick…

rvm install ruby-1.9.2-preview3

gem install rails prawn erubis

… and we’re done.

But is it any faster than REE?

What does it mean to be faster?

Perhaps all I care about is how fast my tests run

rvm use ruby-1.9.2-preview3

time rake

rvm use ree

time rake

# repeat..

My app:

  • Rails 2.3.6
  • rails_xss
  • postgres
  • ~25 models
  • ~25 controllers

My test suite:

Results;

So REE is consistently 10% faster at running my test suite than Ruby 1.9.2-preview3

Does this matter?

Probably not… but maybe I can use those extra 5 seconds.

(can’t wait to see if the Phusion.nl guys can make Ruby 1.9.2 faster… )

Comments (View)

ssh -D is your friend!

Are you stuck behind a firewall?

Does your work block access to facebook?

Do you want to watch English Telly from abroad?

SSH -D is your friend.


All you need to bypass the firewall;

  • ssh access to a VPS
  • ssh -D8080 me@myserver.com // keep this open
  • go to your browser
  • set “connect via SOCKS proxy” on port 8080
  • keep the ssh connection open
  • voila!

Your internet access is now piped via your VPS.

This means;

  • if it is in the UK you can access iPlayer
  • if it is in the US you can access Hulu
  • if you were in China you can access… everything

Boom ting!

Comments (View)

Rails 3 doesn’t allow “open” as a Named Scope

Rails 3 has involved rewriting pretty much the whole codebase,

Rails 3 gives off the fragrance of a coherent, cohesive framework.

But this one kind of annoys me.

/Users/matthew/.bundle/ruby/1.8/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activerecord/lib/active_record/named_scope.rb:104:in `scope’: Cannot define scope :open because AbcDef.open method already exists. (ArgumentError)

So, in Rails 3, when defining a named scope, we can’t override an existing method.

This all makes sense, we don’t want to inadvertently break anything (although I’d hope your test would catch such a thing)

But unfortunately, every object in Ruby has an “open” method… so “open” suddenly is off the market for named scopes… bummer

I spent most of day trying to sort this out… writing a patch… trying to convince people to apply it… but the rails core guys wouldn’t budge.

So here’s a quick hack I put in an initializer

# config/initializers/allow_open_as_a_named_scope.rb
require 'active_record'
class ActiveRecord::Base
  class << self
    alias :_open :open
    undef_method :open
  end
end

And we’re done…

Kind of annoying though. I use “open” all the time, because it makes sense

I’d prefer it if active record just made a logger.warn, and let me make my own decisions

My Fork of rails, My Example of the bug, My Undef_Method hack

Comments (View)

Securing CruiseControl.rb on Nginx

CruiseControl is great

Quick and easy to setup

But takes a few minutes to work out how to secure it.

we start cruise;

cruise@MerlotBuild:~/cruisecontrol.rb$ ./cruise start -d
=> Booting Mongrel
=> Rails 2.3.2 application starting on http://0.0.0.0:3333

Going directly by IP http://94.102.144.37:3333 we get our cruise install.

But that’s not good enough, we need to secure it from the outside world

In Nginx we do this;

server {
  listen 80;
  server_name cruise.matthewrudy.com;
  
  auth_basic "Access";
  auth_basic_user_file /opt/nginx/conf/htpasswd;

  location / {
    proxy_pass http://localhost:3333;
  }
}

And we’re almost done

Except http://94.102.144.37:3333 still works, as mongrel allows requests from any host name

cruise@MerlotBuild:~/cruisecontrol.rb$ ./cruise start -d -b 127.0.0.1
=> Booting Mongrel
=> Rails 2.3.2 application starting on http://127.0.0.1:3333

Does the job… home… secure… safe?

Comments (View)

How big is my MySQL database?

mysql> SELECT table_schema,
sum(data_length) / 1024 / 1024 "data",
sum(index_length) / 1024 / 1024 "index",
sum( data_length + index_length ) / 1024 / 1024 "total"
FROM information_schema.TABLES
GROUP BY table_schema \G;

*************************** 1. row ***************************
table_schema: aardvarks_development
data: 5297.32812500
index: 4407.93750000
total: 9705.26562500
*************************** 2. row ***************************
table_schema: aardvarks_test
data: 0.09375000
index: 0.25000000
total: 0.34375000
*************************** 3. row ***************************
table_schema: badgers_development
data: 13.59375000
index: 16.60937500
total: 30.2031250

as you can see, aardvarks_developpment is almost taking up 10gig

if we only care about “test” databases, we can add a condition on “table_schema”

mysql> SELECT table_schema,
sum(data_length) / 1024 / 1024 "data",
sum(index_length) / 1024 / 1024 "index",
sum( data_length + index_length ) / 1024 / 1024 "total"
FROM information_schema.TABLES
WHERE table_schema like "%_test"
GROUP BY table_schema \G;

*************************** 1. row ***************************
table_schema: aardvarks_test
data: 0.09375000
index: 0.25000000
total: 0.3437500

Boom!

(credit to Paul Butcher for the query)

Comments (View)

Updating RubyGems on Ubuntu 9.04

I don’t know how many times I’ve had to do this.

But every time I install Ubuntu again, I get this;

matthew@Rudyness:~$ sudo gem update --system
ERROR: While executing gem ... (RuntimeError)
gem update --system is disabled on Debian. RubyGems can be updated using the official Debian repositories by aptitude or apt-get.

The simple fix;

matthew@Rudyness:~$ sudo gem install rubygems-update
Successfully installed rubygems-update-1.3.5
1 gem installed
Installing ri documentation for rubygems-update-1.3.5...
Installing RDoc documentation for rubygems-update-1.3.5...
matthew@Rudyness:~$ sudo /var/lib/gems/1.8/bin/update_rubygems
Installing RubyGems 1.3.5
RubyGems 1.3.5 installed

RubyGems installed the following executables:
/usr/bin/gem1.8

matthew@Rudyness:~$ gem --version
1.3.5

From now on you can “sudo gem update —system” as much as you want.

Sweetness.

Comments (View)

Installing Ruby 1.9.1 on Ubuntu 9.04

Now, I’m upset that Jaunty Jackalope doesn’t ship with ruby 1.9.1 as default,
and the packaged version is only 1.9.0.

So we’re going to have to build it from source.

And because we’re all progressive people, we’re not even going to worry about suffixing the executables with `1.9` I can’t be bothered to type `gem1.9`

The dependencies are simple;

sudo apt-get install build-essential libssl-dev libreadline5 libreadline5-dev zlib1g zlib1g-dev

Then the usual process…

mkdir ~/src && cd ~/src
wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p0.tar.gz
tar -xvf ruby-1.9.1-p0.tar.gz
cd ruby-1.9.1-p0
./configure
make
make test
sudo make install

And to get rails working properly

sudo gem update --system
sudo gem install rails

# and to get sqlite3 working properly
sudo apt-get install sqlite3 libsqlite3-dev
sudo gem install sqlite3-ruby

Done.

I’ll add to this if I notice any problems

Comments (View)

Ruby 1.9 becoming the standard?

There’s a lot of talk recently about pushing the Ruby Community onto Ruby 1.9.

Now that’s cool, the more people using 1.9 the quicker the issues will get ironed out

(people need to be spurred into fixing their libraries)

But there is one thing standing in the way of 1.9 being adopted by the whole community, Default Packages

Mac OSX comes with 1.8.6 as standard, Ubuntu 8.10 comes with 1.8.7.

Whitney Houston said “the children are our future”, and that’s exactly who we need to start using 1.9 right from the word go.

With Ubuntu 9.04 (Jaunty Jackalope) and OSX Snow Leopard on their way out soon, surely if they adopted 1.9 as the default, we’d be on the road to success.

However, maybe that’s not going to happen.

A quick look at the packages of Jaunty Jackalope and you’ll see

This package is a dependency package, which depends on Debian’s default Ruby version (currently 1.8.x).

So I guess this thing’s not going to get fixed soon.

Comments (View)

Expire eTAGs when you redeploy

Rails 2.2’s eTAG functionality is great.

def show
@article = Article.find(params[:id])
if stale_record(@article)
# do something expensive
end
end

protected

def stale_record?(record)
fresh_when(:etag => [current_user, record], :last_modified => record.updated_at.utc)
!request.fresh?(response)
end

“304 NOT MODIFIED” all around!

But this determines freshness based on just the record.
If I deploy a new version of the “show” template eTAG-compliant browsers won’t refresh.

I could build my own way of handling this inside “stale_record?”
But Rails already has a method for dealing with this.

All cache keys are generated through the following code.

if ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
expanded_cache_key << "#{ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]}/"
end

So what does it mean to be the RAILS_APP_VERSION?
Well, I’m going to mis-use it, and say “it’s the current version of our app”

And Capistrano already gives this to us… it gives us /current/REVISION!!!

Perfect!

A quick “/config/initializers/capified_etags.rb” later

app_version_path = File.join(Rails.root, "REVISION")
if File.exist?(app_version_path)
ENV["RAILS_APP_VERSION"] = File.open(app_version_path).read.strip
end

Nice.

Let me know if there are any other approaches out there.

Comments (View)