DEV Community

Cover image for An Intro to Ruby Gems
milandhar
milandhar

Posted on • Edited on

An Intro to Ruby Gems

As beginning Ruby programmers, we often use gems subconsciously. We can throw binding.prys left and right to debug our code, but it is possible to get deeper into the landscape of Ruby without truly understanding what the Pry gem really is or where it comes from. Since starting working with Ruby at the Flatiron School, I've noticed our labs and projects have included Gemfiles with longer and longer lists of gems, and we have begun using increasingly powerful gems such as ActiveRecord, Sinatra and Rails. I realized that gems add a practically infinite amount of free leverage to our Ruby code, but many aspects still seemed mysterious. Before continuing into the journey of Ruby-On-Rails, I wanted to make sure I had a solid grasp on what gems are so that I know how to maximize their potential and also manage bugs ... hence, this blog post!

While we won't delve much into the functionality of individual gems, this post will introduce you to what Ruby gems are, some quick tricks, and how to utilize them to their full potential.

Ruby Gem GIF

What is RubyGems?

RubyGems is a package manager for Ruby that provides a standard format for distributing Ruby programs and libraries (aka gems). RubyGems is the tool we use to create, share and install gems.

What is the structure of a Gem?

Gems include the following components: Code, Documentation, and gemspec. All gems follow the below structure of code organization:

Imgur

Finding Gems and Useful Commands

The RubyGems.org website is the best place to find gems in most situations. However, you can also search RubyGems' repository through the terminal using gems search -r.

The --local option limits the search of gems to only those installed on your machine. For example, gem search -r rails --local returns the following list of gems installed on my computer:

Imgur

To install a gem use gem install [gem name]. You can browse through all your installed gems using gem list.

There is also documentation available inside your terminal through gem help.

gem help commands is useful because it displays a list of all available gem commands.

Bundler and Gemfiles

What is Bundler?

Currently a month into life at Flatiron, I have probably coded the word bundle over a hundred times, but rarely stopped to deeply understand what it does and why it is so useful. According to its page in RubyGems, Bundler is a gem that "manages an application's dependencies throughout its entire life, across many machines, systematically and repeatably." It provides a consistent environment for Ruby projects by tracking and installing the exact versions of gems that are needed to run an app. Without Bundler, it would be a nightmare to keep track of all the required dependencies necessary for a project, but Bundler ensures you have the correct gems for development, staging, and production. To install Bundler, simply run $ gem install bundler from your terminal.

What are Gemfiles?

A Gemfile is a format for describing gem dependencies for Ruby programs. Gemfiles are placed in the root directory containing the associated code. At the top of the Gemfile, you must add a line for the RubyGems source containing all of the gems necessary for the project:
source "https://rubygems.org"

Name

The real purpose of the Gemfile is listing the individual gem requirements, each on a separate line:
gem 'pry'
gem 'rails'
gem 'bootsnap'
gem 'byebug'
gem 'rspec-rails'

Versions / Groups

Each gem can have one or many version specifications:
gem "pry", ">= 0.10.3"
gem "nokogiri", ">= 1.10.1", "< 1.10.3"

Each gem may also specify a group to which it belongs. If no group is specified, it will be placed in the default group.
gem "pry", :group => :test
gem "wirble", :groups => [:development, :test]

Installing Required Gems

The real power of Bundler is the simplicity it provides the user to install all the required gems to run an application. All it takes is a quick bundle install and all gems specified in your Gemfile will be installed.
You may also specify a group of gems to skip during installation using --without. For example: $bundle install --without production should be used if using a database in development mode that is different from one being used in production.

Gemfile.lock

The Gemfile.lock is another file that I'd noticed hanging out in the root directory but overlooked, assuming I'd never need to open it. I was wrong!

What is Gemfile.lock?

Gemfile.lock is a snapshot of the versions of all gems in the Gemfile at a single point of time.

In our Gemfile, we write dependencies as below:

gem 'sqlite3', '~>1.3.6'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'

The ~> symbol has a special meaning in the Gemfile. What gem 'sqlite3', '~>1.3.6' means is "we want any version of sqlite3 as long as it's greater than or equal to 1.3.6 and less than 1.4." Similarly, gem 'sass-rails', '~> 5.0' means "we want any version of sass-rails as long as it's greater than or equal to 5.0 and less than 5.1." If we built our app a year ago and today sqlite3 is on version 1.4.1, running bundle install today could pose issues (assuming no Gemfile.lock). It's possible the current version of sqlite3 would break our app or a feature that was available in the previous version is no longer available, etc. This is where the Gemfile.lock comes in!

In Gemfile.lock, only the exact versions specified get installed when running bundle install. So if you distribute your app with a Gemfile.lock, every machine will use the exact same version of every gem, providing the stable deployment stack.

How to Create a Gemfile.lock

Easily! A Gemfile.lock is automatically created when running bundle install for the first time. After that, every time you run bundle install, Bundler will first look up the Gemfile.lock and install the versions specified there.

If you would like to update the gems in your Gemfile.lock to the newest version, you can update the dependencies to the exact versions you want in the Gemfile, and the next time you run bundle install the updated versions will reflect in the Gemfile.lock.

It is a best practice to check your Gemfile.lock into git, so that every machine that downloads your app also has your Gemfile.lock, is using the same versions of every gem and doesn't need to resolve all dependencies individually.

A Bundler Bug Example

More recently, I have run into some issues with our labs where the Bundler version specified in the lab is preventing the correct installation of other necessary gems.

In one recent lab, the Gemfile.lock was bundled with an old version of Bundler (1.16.1), whereas the current version is 2.0.1.
Below is a snippet from the Gemfile.lock in the root directory:

Imgur

As you can see, the Gemfile.lock includes the old (1.16.1) version of the Bundler gem.
When attempting to run bundle install on this lab, I received the error message below:

Imgur

We are prompted to install nokogiri-1.8.5 since capybara was resolved to v 3.10.0 and it depends on old nokogiri, however there are several dependencies that prevent the nokogiri-1.8.5 installation from succeeding, and it turned out that installing those dependencies also did not resolve the problem. The issue here was that the Bundler (1.16.1) was specifying a version of nokogiri I could no longer download. As a result, I tried running a bundle _1.17.3_ install using a slightly later version of Bundler I had on my computer (1.17.3). Running a normal bundle install would just use the version of Bundler specified in the Gemfile.lock (1.16.1 in this case) and keep requesting the version of nokogiri that doesn't work. But specifying the later version through bundle _1.17.3_ install requests for many dependencies to be installed using slightly later versions, and hopefully will move the nokogiri version past 1.8.5. Alas, I now got a different error that my bundle _1.17.3_ install command requested nokigiri >= 1.10.0 but the current bundle has nokogiri locked at 1.8.5 - making progress! :

Imgur

After taking the error message's advice and running a quick bundle update nokogiri using Bundler (1.17.3), I was able to get nokogiri updated to 1.10.3. Then I just ran a simple bundle install, and all dependencies installed correctly including the correct version of capybara - the lab was good to go!

Imgur

Conclusion

I hope this post provides a helpful reference for you as you continue your journey into Ruby-On-Rails. And ideally the bug example I walked through demonstrated the utility of being familiar with gems. There are many sources of truth online where you can find help on gems, but ideally this acts as a single repository for that knowledge, and can help you optimize your interactions with gems and stomp some bugs! Feel free to post questions / comments below.

Thanks for reading!

I used the below references in this post:

https://rubygems.org/gems/bundler/versions/1.11.2
https://bundler.io/
https://bundler.io/man/gemfile.5.html
https://stackoverflow.com/questions/6927442/what-is-the-difference-between-gemfile-and-gemfile-lock-in-ruby-on-rails/10959764
https://www.realifewebdesigns.com/web-programming/rubyonrails/gem-bundler.asp
https://www.ruby-lang.org/en/libraries/
https://en.wikipedia.org/wiki/RubyGems
https://stackoverflow.com/questions/8699949/what-does-the-symbol-mean-in-a-bundler-gemfile

Top comments (3)

Collapse
 
ceciquin profile image
Cecilia Quintana

Excellent Article! thanks for sharing . I'm new at Ruby development and it's being an interesting journey so far ( and hard) . I think that this language helps you to sharpen awesome development skills as packaging and versions file. On the other hand, I do have a question ( I know that this is not "Stack Overflow" 😛 ), recently I was deep diven in an artifactory server that has a gem to help managing the deploy of artifacts... the thing is that I created a gem (a personal gem) and when I want to push the gem to this "artifactory server" I received an argument error throw by a JSON gem ( this gem is required in the "artifactory server" gem), I checked the gems list installed and I notice that I had 2 versions of the JSON gem, this could be the problem ? any extra idea about what could be the issue or how to troubleshoot this kind of problems between gems?

Collapse
 
1kazuza profile image
James Kazuza Jr.

Hello,

This article help me in my first time experience with Ruby.

Thanks!

Collapse
 
milandhar profile image
milandhar

Thanks for reading James!