RAII is a usage pattern: You must stack-allocate an object or wrap it in a suitable smart pointer. It's just as easy to do things differently as it is with Ruby's blocks or C#'s using statement. The reason it has a name is because it is a pattern that's talked about so much exactly because following the pattern is so intrinsic to modern C++ programming.
Once you're passing a block to a method like this in Ruby, the execution of the cleanup code is just as guaranteed as it is in C++.
I don't agree completely. As I said, you cannot leak the fd without leaking the memory of the object. This means that in C++ you get the correct behavior as long as you take care of the lifecycle of your objects correctly. You don't need to do stack allocation or smart pointers as long as you de-allocate the object when your are done with it. So the lifetime of the fd is tightly bound to the lifetime of the wrapper instance. If you stack allocate without deallocation you have a bug _anyway_ in your C++ program, thus I would like to argue that it is a problem of manual lifecycle management, not a flaw in the RAII implementation.
You do however have a point when you say that you can miss deallocation and that is just as easy as forgetting to put a variable in a block. In an ideal world I would like to be able to decouple de-allocation time from destruction time, as someone mentioned above they are completely orthagonal issues. If this would be possible, one could guarantee the destructor callback, but defer deallocation until later. This would probably give leeway to more effective memory allocation patterns while keeping RAII alive.
And another thing about blocks: how do you deal with trees and graphs of objects? That is not trivial when using blocks. You can get around it, but continuing that way would most likely lead you to something like Haskells monads (the "programmable semicolon" aspect of them).
Once you're passing a block to a method like this in Ruby, the execution of the cleanup code is just as guaranteed as it is in C++.