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
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… )
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!
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
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?
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)
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.
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
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.
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.