Now, you all know that I do not think that Ruby has ANY problems with scaling. However, applications such as basecamp have a huge advantage for scaling: minimal shared data.
The key to scalability is minimizing access to the same data. The less anal you are about how "correct" the data is the better you will be.
Microsoft Word scales very well as when a million people are writing a document, they are not editing the same one (I know, they could be on a shared drive blah blah).
Caching and all of the tricks are ways in which we can cheat the system. We can make copies of our REAL data and access those instead. This works for a lot of applications, and a lot of data. This is why you see "this stock data may be up to 15 minutes old". Imagine if everyone needed access to the stock price right NOW. I mean NOW. I mean.....
To scale probably, you want to minimize any locking. How stale can your data be in different aspects? The more stale that you can deal with the better.
Where does Basecamp and company fit in here?
One of the great advantages to those applications is that there is little shared data.
If I sign up for an account for my company I can have a large amount of data on fooinc.grouphub.com. Someone else can have barinc.grouphub.com, and no data is shared. I do not need (or should be allowed) access to their data.
This means that if they wanted too, we could be on two different machines with out own MySQL instance. One per user doesn't make sense of course (unless the users are GE and Ford), but how about splitting up: A-M and N-Z.
If load keeps going up you split again, and again, and again.
If you are in this situation you are a lucky man, and should be able to scale up anything :)
If you have an application where there is more shared data then you may need to get more creative. A lot of web apps are heavy on reads so you can scale up nicely via MySQL replication and putting out more slaves, but at some point the master will not be able to handle the writes. This is when you need to Give the DB a break! and use caching, and tweaking your archicture into pieces.
We do this with out Rails apps by making parts and pieces web services that we can scale up separately, but there is always the bottleneck on some part of the darn data!