rbenv or bundler gemset sandboxing? - ruby

The rbenv documentation states that you can use the gemsets plugin to sandbox your gems if you aren't using bundler:
Manage gemsets. Bundler is a better way to manage application dependencies. If you have projects that are not yet using Bundler you can install the rbenv-gemset plugin.
However, I am using bundler and when I switch between projects that have different gemsets I need to re-bundle. When I was using rvm, this was simple due to the .gemsets file.
Is there a sandboxing functionality in bundler that I am not aware of or have I misunderstood the documentation?

I found this clear, well-documented solution:
Setting up and installing rbenv, ruby-build, rubies, rbenv-gemset, and bundler
Now when you gem install (see “Bundler” section below) something it will go to your helloset gem area.
You can combine use of multiple gemsets with it.
The big benefit to this setup is enabling each project to use a different set of differently versioned gems.
Read the section entitled Enable RVM-style “gemsets” (optional).
It uses the rbenv plugin for gemsets: https://github.com/jamis/rbenv-gemset.
Update 8/12/2012 I am using this to manage two projects with different versions of Ruby, and separate sets of gems. It works well.

bundler uses the Gemfile and Gemfile.lock files in, in essense, to make a "gemset" for that particular project that you access via commands prefixed with bundle exec

It may have to do with the way rbevn uses shims. You might want check out
https://github.com/carsomyr/rbenv-bundler

Try using chgems with Bundler. chgems is like chroot for RubyGems. It spawns a new sub-shell with PATH, GEM_HOME and GEM_PATH updated to use $project/.gem/$ruby/$version as the primary GEM_HOME. Since all gems are installed inside of the project directory, cleaning up after a project is as easy as rm -rf $project/.

Related

Is it recomment to install ruby dependencies into local folder?

I'm learning ruby recently and I'm a front-end developer, I found the dependecies are installed to C:/Ruby31-x64/lib/ruby/gems/3.1.0 folder when I use bundle install. it seems dependencies are installed globally by default like the npm install -g. I know that Bundler also have a way to install the gems to the local folder, so I wonder is
it recommend to install the dependencies to the local folder like npm does?
Similar to Composer, Bundler takes care of maintaining your dependencies, but rather than installing everything in the project folder, it distributes your gems system-wide, which are then shared by all of your projects. Using the Gemfile in your project folder, it keeps track of which libraries each project needs. Bundler is the default package manager for Rails, so you should simply let it do its thing. It does it quite well.
Hope this helps.
Use a Version Manager for Ruby, and Bundler for Gem Version Management
There are occasionally reasons to install gems in from one another isolation, but most often you should use a Ruby version manager to manage your non-system Rubies and Bundler to handle multiple gem versions and locations. Avoid modifying your system Ruby or its gems whenever possible. Also, be aware that even using RVM gemsets (or similar features in other version managers) without tweaking some poorly documented features like rvm gemset globalcache enable can create a level of isolation that is likely unnecessary and can bloat disk usage dramatically.
If You Need Gem Isolation...
That said, if you want to ensure you are isolating your gems or localizing them to your application and aren't using direnv's Ruby layout to manage all the various environment variables involved, you can use Bundler's BUNDLE_PATH environment variable to "vendor" your gems into the local application directory (these days usually under vendor/bundle). For deployments or containerization, you can also invoke bundle-install with the --deployment or --standalone flags and a list of gem groups to install if you don't want to rely on the availability of Bundler itself after installing the gems.
This sort of thing might be useful for building containers or tarballs, but isn't really very useful for development. Don't do it unless you have a really strong reason.

Cleaning gems from older gem version

I recently upgraded my distro (Ubuntu from 16.04 to 18.04), and I guess either on the upgrade or on the regular sudo update/upgrade calls gem was upgraded and I currently have the 2.7.6 version. I barely use Ruby lately, but just now I had to run a jekyll/bundle command which returned me that it had a bad interpreter (it was looking for ruby2.3 and it's currently installed on the 2.5 version).
My next step would be updating the jekyll and bundle gems (so they update the interpreter version), but to my surprise they aren't listed when I run gem list. They were obviously installed since there's a /usr/local/bin/jekyll executable and a /usr/local/bin/bundle one as well. But I think when gem was upgraded it started checking gems on a different folder (/var/lib/gems/2.5.0 I'm guessing) but jekyll/bundle apparently are in /var/lib/gems/2.3.0. I'd be fine just installing jekyll/bundle on the 2.5.0 version, but is there a way to remove all gem files from the older version since they are useless now?
I highly recommend you to use a ruby version manager like rvm or rbenv to manage different ruby versions installed on your system.
If you just want to remove the gems from your disk, you can find the location of each gem with the command bundle show $gem_name and delete the parent directory to delete all of them. You may need to delete the Gemfile.lock as well to reset the locked gem versions.
Here's what I recommend:
Use rbenv for multiple Ruby version management, no customizations needed
a ruby installer plugin is now included with rbenv
it also handles ruby executable shims automatically, don't need to rbenv rehash anymore
it loads really fast (rvm has a noticable load time on shell startup)
Use bundler to dynamically resolve gems at runtime (options below)
it's fast enough anyways
don't need a special gem solution, bundler comes included /w Ruby now
Options to invoke bundler dynamically (I recommend the last one):
use bundle exec in front of every ruby executable
variant: create alias be='bundle exec'
create bundle binstubs <LIST GEM EXECUTABLES YOU WANT> for each project
use bin/ in front of every ruby executable to call the binstubs
do #2 and then set up .git/safe
lets you manually allow PATH lookups to the bin/ folder while in that project root
don't need to type bin/ anymore
Now multiple gem versions will all be installed into the same Ruby version bucket, and you let bundler dynamically add the right versions to the load path before every startup.
Removing a Ruby version will also mean removing all the gems (and versions of those gems) installed for that Ruby version as well.
I'd like to thank both answers. I upvoted them because even though they're not a direct solution to my problem they give good directions to prevent it.
NOTE: These are the steps I took, which doesn't mean they are the correct way, so don't take more as a reference than a guide.
Here's what I did to clean up those old Ruby version gems:
First I needed to add an environment variable for gem to be able to find those obsolete gems, by running GEM_PATH=/var/lib/gems/2.3.0.
Then it's possible to get the contents and specification of the gems with gem contents name_of_gem and gem specification name_of_gem.
I individually uninstalled those gems that were obsolete with sudo GEM_PATH=/var/lib/gems/2.3.0 gem uninstall -i /var/lib/gems/2.3.0 name_of_gem. In my case I did a sudo install, so I needed sudo which also required me to set the environment variable again because of sudo's security policy. Also, I needed to manually set the install directory for some reason.
Some gems will have executables, and the uninstall will ask if you want to remove it. I wasn't able to get the gem uninstall to remove it because it claimed I didn't have write permission to /var/lib/gems/2.3.0/bin (which is weird because the EXECUTABLE DIRECTORY gem environment variable was /usr/local/bin). I asked gem not to remove the executables, wrote down their names and removed them manually from the EXECUTABLE DIRECTORY folder. You can also use which gem_executable_name to find out where it's located.
After uninstalling all the gems I believe it's safe to remove the /var/lib/gems/2.3.0 folder and its contents. Running gem contents on all of them only returned me files on this folder so I believe the only external files were the script/executables that were added to /usr/local/bin.

how to use rbenv to manage local gems

I've been using Middleman since a while, but very recently it is getting some issues in loading.
This is likely due to the coexistence of very old gems of the same type.
Have to say that I did follow some online suggestions, but haven't really got the full understanding. So ended up using rbenv for managing ruby then bundle to install the gems.
Now, have two project that for which I need to "reset" and install only the referenced gems into the local folder or somehow they don't conflict.
I can't figure out how to do it.
Using the rbenv -local I can change the local ruby version, but not sure how to move next.
Any help?
Thanks
I don't think you need rbenv or rvm for this, although their are good tools. To run a piece of code with just the gems you need, and the versions you specified in your Gemfile, run any command prefixed with bundle exec.
For example bundle exec middleman server.

How to install a gem so that it executes independent of currently active RVM gemset?

I am writing a dev command-line tool gem (let's say called "tool") which I would like to use in any place in the system. I use RVM for different projects, but this tool should be available from the command-line inside those projects.
If I simply install the gem globally using "gem install" (let's say it installs to /usr/local/bin/tool), the executable is of course available inside of other projects, but since the gemset changed when executing "tool" it fails saying that it cannot find the "tool" gem (because "tool" was never installed to that gemset). I don't want to add the gem to all the Gemfiles of all the projects.
What's the best way of dealing with this? Perhaps there is a way to "lock" the gem_path/gem_home in the executable at the time of installation?
It turned out that https://github.com/sportngin/brew-gem does what I want, installing a Rubygems gem via brew and locking its GEM_HOME and GEM_PATH in a bin wrapper it generates, so that everything works even when executed in the context of a different RVM gemset.
I forked it into https://github.com/gtmax/brew-gem, adding support for installing a brew gem from a local.gem file or from a gem project on github.

What does Bundler offer over RVM?

I am not sure what the differences are between these two tools. There seems to be a big overlap, but I have been using RVM and facing some miss-compatibility issues.
What does Bundler do that RVM does not?
They serve different purposes. RVM creates a sandbox to manage your Ruby installations. As a part of that, it also lets you define gemsets.
Bundler doesn't manage your Rubies, it works with the currently selected Ruby.
So, I think you should consider RVM as the configuration manager for your development environment, and Bundler the gem manager for an application.
EDIT: Additional thoughts -
Whether we use RVM or not, typically we'd have to load all the gems we're going to use for an app by hand, using gem install blah, for every gem we want to use.
I end up managing my gems across multiple Rubies by hand. Once they're installed I can create gemsets using RVM, but RVM won't automatically retrieve a particular version of a gem if it's not installed, or go get it again if it was removed. Because RVM is more concerned with your Ruby environment, it mostly leaves the versioning of gems to gem and to us.
Bundler, on the other hand, does care about those missing parts in RVM. When you create the Gemfile for bundler, it will retrieve the necessary gems and specific versions if specified. So, the task of installing a Ruby app on a different machine becomes much simpler. Push the files to the other machine, then run bundle install and it'll do the rest.
It works nicely with Rails and is a sensible solution for my production files. It will be much simpler than how I have to handle Perl distributions in order to run Perl apps on the same hosts.
RVM is more like a containment unit. While Bundler is like a manifest (dependency manager) of what the application will require or use in it's lifecycle (among other things).
If you are working in Rails, you will not be able to escape Bundler. But I use it all the time just so I know what Gems I'll need, and so will others who later come into the project.
RVM helps me separate out my Rubies and then further into Rubies/projects. This way I don't have a slew of Gems and different versions all in one pile.
Not exactly the most action packed answer, but hope it helps a little.
To directly answer your question...
What does Bundler do that RVM does
not?
Bunlder will install all gems that are needed by a project (that uses bundler, and have all needed gems specified in a Gemfile). RVM does not do this.
Using the Gemfile you can specify what gem groups (ie: development, testing)...
There are many 'small' things like these that bundler does but RVM does not. In general as the good people above explained, RVM has a different set of goals from that of bundler. RVMs about managing ruby runtimes while bundler is about managing dependent gems for a application.
Bundler is a tool for managing dependencies in your code -- i.e., all the gems it requires. It will make sure that all the gems you specify in your Gemfile, and any dependencies, are installed on your system. It doesn't really care which version of ruby you are using, it just installs the gems for you under whichever interpreter is in use.
RVM is a tool for running multiple rubies, and in theory, multiple gemsets as well. It doesn't handle dependencies for you at all -- it's still up to you to install the gems.
My experience (and I'm new to RVM), is that you don't want to bother with RVM unless you have a need for running multiple rubies, or need gems installed for different projects that somehow conflict with each other. Even if you are using RVM, it makes sense to use Bundler to manage gem dependencies so that your Gemfile can be tracked in whatever code repository you are using.

Resources