Gem update problems again and again and again

Why is it that Ruby fails in the most unpredictable ways when I call gem update?

I can have a working Ruby with all my gem packages working nicely together but if I try a gem update I have no faith that bundle gem [enter gem filename here] will work or rails new [enter rails projectname here] will work or etc.

gem update should work flawlessly because that’s basically its job. I shouldn’t have to be a gem package manager every time I call gem update.

Why is gem this way?

There are two problems with Rubygems:

Native Extensions

Gems will not fail if they are written in pure Ruby. But Ruby doesn’t have the capability to even do the most basic job like utilizing Linux / Windows kernel API let alone using ffi or postgresql. In such cases, you have to integrate some C, C++ (and sometimes Go, Rust, Crystal etc.) code that will perform the low-level task. For example, some days ago Rubygem ffi on my system failed because I updated libffi on my system, it has nothing to do with Rubygem. If you use postgresql or sqlite3, you use postgresql-libs or sqlite library, and gem install builds on that version.

But because Rubygems and your system’s library are not united, the package manager of your distribution will let you uninstall the libraries if you don’t need them. You can uninstall postgresql-libs without uninstall Rubygem postgres, in such case, postgres will not run, and also during an update, it will fail to build the native extension.

Also, imagine you build gems with GCC or Clang, if you uninstall the compiler, gem update will fail because it can’t build the native extensions that are written in C or C++.

So, the solution is you must keep in mind that you have Rubygem X so XLibs is necessary, and GCC / Clang is necessary because you use native extensions. No system-wide automatic way of doing that, because the package managers are different. So yes, there’s no reliable way to install a gem reliably.

The Gem Depends on Other Gems

See, the gem community is huge. Say you have published your own gem, but you don’t active maintain it nowadays. Your gem depends on some libraries, say, ffi for the sake of it. Now, for some reason if ffi yanks their old version that you were depending on, your app will not run because nobody can install that yanked version.

Sometimes, you see the worse, you update all gems, and suddenly you find some other library breaks. This happens because that library can’t work with the new version of API. For example, if you have a library, and it returns you the CPU usage as an array: [50, 60, 23], and in the next major release, it starts returning has with core numbers: {0=>50, 1=>60, 3=>23}, your app totally breaks. And this happens often! Now because you are maintainer of the library that broke, you must update that, or you are bombarded with issues on your issue tracking system.

And heck, my system breaks whenever I update my Archlinux system partially, and some ‘so’ libraries are updated while others aren’t. In this case, due to soname bump, the other packages will not work, even your system may refuse to boot. But that happens when I partially update packages. In case of Rubygems, when you update some system library that the gem depends on, it’s just like the partial update. You must track what you updated, and rebuild the gems, or fresh install the gems.

Both of these issues are really common in Ruby, Python and Node. And the worst part is that, the more dependencies you have, the more your app might break due to such breaking changes. And this issue is way more common in NodeJS, because in NodeJS a package depends on 100 other packages (although that depends on how lazy the developer is to implement functions from scratch)! I once installed bootstrap with VueJS and found that bootstrap will not work with VueJS 3.0. So this issue exists due to dependencies.

So we are in this situation altogether, it’s nothing new, it happened 10 years ago, and it still happens now. So there’s no way to get out of this situation unless you write everything from scratch, including your OS!