Shell script to switch between MRI and jruby - ruby-on-rails

Working on a project which uses jRuby, but locally when I work I often use MRI because it's faster.
Now switching between to is a major annoyance, this is how I switch from jruby to MRI:
rvm use ruby-2.1.5
sed -i.bak 3s/.*/ruby" '2.1.5'"/ Gemfile
Which replaces my Gemfile and specifies the right version of ruby. Now I wanted to create two executables from bin/ folder of my rails project, one called mri and another one jruby so I could switch back and forth between the two using a single command, and so that everyone who work in a team can use the same.
Problem with this is that, when the shell executes, the RVM doesn't change the ruby version in my current session. So naturally I get this message :
Your Ruby version is 2.0.0, but your Gemfile specified 2.1.5
Is this a good approach to what I'm trying to do?
pretty sure I'm not the first person trying this
Do you already have something that works for you?

As the comments pointed out, you need to re-source the rvm scripts.
You probably could just source ~/.bash_profile or ~/.bash_rc again, as they should be sourced there.
That being said, I haven't had this problem with rbenv, but I only swap between MRI versions.
There is also a spec for a .ruby-version file see here that both RVM and rbenv honor.
For bundling bin stubs you can specify a bin path with bundle binstubs --path mri-bin.

Related

How to use rbenv and store gems locally - coming from rvm background

I used to use rvm and I want to start trying out rbenv.
From what I understand, rbenv does not have the same isolation built in when it comes to gems, it is only managing your ruby versions.
I know there is a rbenv addon that handles gems, but I dont' NEED to get it correct?
I can still download gems locally to my project and use bundle exec for each command?
Is there a short cut that I don't have to be so verbose when typing my commands?
Please explain the workflow as I dont' want to assume anything.
Update
I'm confused how to get the gems loaded into a separate folder.
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.

Is there a version manager for Ruby gems?

I'm a new Rails developer. I recently took a class on Rails and now I'm trying to make sure I'm growing in my skill by self-assigning projects that push me. One thing I'm trying to do now is use Radiant CMS to build a blog site. However, I'm running into some problems downloading the Radiant gem. Here's what I did:
When I first tried gem install radiant, it installed most of the required gems but then threw a warning (which I unfortunately did not save verbatim), which was along the lines of:
railties executable will overwrite rails executable. Overwrite? Y/n
Stupidly, I chose "Y". As soon as I did I tested my rails gem by writing rails new testproject and it failed. So I then re-ran gem install rails, told it to overwrite the "railties" executable, then ran gem uninstall radiant to get rid of the core radiant gem (although I do still have railties).
Now, my Rails gem is fixed, and I can create new Rails projects without an issue. However, I reinstalled the Radiant gem, and while it installed, it fails to create a project every time I run it.
I'm pretty sure I broke something, but I'm not terribly concerned about that. What I am concerned about is the fact that it seems that the Radiant gem doesn't really coexist well with the Rails gem, which leads me to my question:
Is there any way to create separate, self-contained ruby gem environments where the current Ruby version will only use the gems in the specified environment?
In essence, I'm looking for what rbenv does, but for collections of gems rather than Ruby versions.
Currently, I have Homebrew installed and I am using rbenv as my version manager. Everything I can find so far talks about managing gems on a project-by-project basis; I'm looking for something that will manage and keep separate the gems that create the projects in the first place. So, for example, environment_a contains rails and httparty while environment_b contains radiant and railties.
I'm not above completely obliterating rbenv and all of my gems and starting from scratch, either, so that's a possibility (and an advantage of being a noob).
You should check bundler, as it does exactly what you need.
Yes: rbenv-gemset
I think that it is better than RVM because it is less invasive.
I have been using rbenv and rbenv-gemset for about 2 years and find it easy to use. It makes it easy to encapsulate the Ruby and gemset in a project, run multiple Rubies and gemsets on one machine, and move a project to another machine.
You can use ruby-build to install other versions of Ruby. There is a trick to installing the latest versions of Ruby.
You may want to have a look at How do I ensure ruby gems are installed in right place to be executed by bundler? It has some relevant (and hopefully useful) info.
Yes, there is.
I think that it's called RVM.
Just like Chris Heald said, You can check more information about it # rvm.io/gemsets/basics
I'd recommend bundler for versioning gems although both RVM and rbenv also have this functionality.
You asked: "Is there any way to create separate, self-contained ruby gem environments where the current Ruby version will only use the gems in the specified environment?"
The best way to do it with rvm is entering your project's directory and then run:
rvm use ruby-x.y.z#your_project_name --ruby-version --create
where x.y.z is your Ruby version for that project, previously installed with rvm install x.y.z
For example, to use the newest Ruby version with a project named acme you would use
rvm install 2.3.1
and then
rvm use ruby-2.3.1#acme --ruby-version --create
This command would create two files in the projects directoty: .ruby-version and .ruby-gemset.
The file .ruby-version would contain just the version number. And the file .ruby-gemset would contain only the name off the gemset, the same name of your project (acme).
It happens that rvm is smart enough to check for these files and use the gemset specified, which will be located at ~/.rvm/gems/ruby-2.3.1#acme and your gems will be located at ~/.rvm/gems/ruby-2.3.1#acme/gems.
Some points:
1) Using your project's name as the gemset name is NOT mandatory. You may use anything you like. It's kind of a standard using project's name, but not mandatory.
2) rbenv probably has a way to do the same, but I don't use rbenv and really don't know how to do that.
Hope this answer helps.

rbenv: Surviving without gemsets

TL;DR
Don't bother with gemsets; multiple versions of a gem may be installed concurrently.
When necessary, specify which version to execute using $ gem-based-binary _version_ args notation.
Use bundle exec when you have a Gemfile specifying the version.
gem install rails -v 3.2.13
rails _3.2.13_ new Project2
cd Project2
bundle exec rails server
UPDATE: 2015-06-04
I wrote this question three years ago. Partly, it was based on a false assumption, and partly the situation has changed since then. With appreciation to #indirect for his original answer, I want to call attention to #kelvin's newer (less upvoted) answer, summarized above.
My false assumption: Only a single version of a gem could be installed at a time, hence the need for gemsets to isolate the namespace. Not true. Multiple versions of a gem may be installed concurrently. The most recent one will be used when invoked from a command line, unless you have a Gemfile specifying the version constraints and invoke the command via bundle exec, or specify the version as its first argument.
See also How can I call an older version of a gem from the commandline? re: the underscore-version notation.
Original question:
I have multiple projects going on using different versions of Rails. I have a workflow (described below) for creating projects using specific versions of rails, and keeping the projects isolated from each other. I'd like to experiment with other workflows, in particular, using rbenv instead of RVM, but it's not clear how to do so.
QUESTION: What is the best current practice for creating multiple rails projects, each using a different version of rails, when making use of rbenv and bundler, as opposed to rbenv-gemset or rvm?
USE CASE: I have two rails projects, called ProjectA and ProjectB. ProjectA is developed using one version of rails ("RailsA"), whereas ProjectB uses a different version ("RailsB"). How do I manage having both versions installed?
THE GEMSETS APPROACH: When I first started with Rails development, I used RVM. In addition to supporting multiple, concurrent installations of ruby, RVM supports having multiple Named Gem Sets. Each project has its own independent collection of gems (including rails itself) called a gemset:
rvm gemset create RailsA
rvm gemset use RailsA
# RailsA. Note: My question is not version-specific.
gem install rails --version 3.0
rails new ProjectA
cd ProjectA
rvm --rvmrc use `rvm current`
vi Gemfile
bundle install
cd ..
## Now do the same for ProjectB
rvm gemset create RailsB
rvm gemset use RailsB
gem install rails --version 3.2
rails new ProjectB
cd ProjectB
rvm --rvmrc use `rvm current`
vi Gemfile
bundle install
Note: The very creation of the project folders should be done (IMHO) by a rails new command using the desired version of rails, since the skeleton files change from version to version. (Perhaps I should revisit this premise?)
THE BUNDLER APPROACH: I've been playing with using rbenv instead of RVM, but I don't understand the workflow as clearly. In the README.md, Sam Stephenson writes that "rbenv does not ... manage gemsets. Bundler is a better way to manage application dependencies." There is a plugin (rbenv-gemset) for getting the same results as rvm's gemsets, but Sam clearly favors using Bundler instead. Unfortunately, he doesn't elaborate on what the workflow would look like. Even the Bundler website doesn't explicitly connect all the dots of how to isolate one project from another. Several blogs and gists come to the rescue, suggesting the following ~/.bundle/config file:
---
BUNDLE_PATH: vendor/bundle
(BTW, I'm not sure what the "---" is about. The docs make no mention of it and it doesn't seem to make a difference.)
This effectively gives each rails project its own gemset, storing the gems in ProjectX/vendor/bundle/. In fact, rails itself will be (re-)installed there, making the project completely independent of the rest of my environment, once I run bundle install.
But the elephant in the room is the chicken-and-egg problem of creating the rails project folder in the first place!! In order to create the ProjectA folder using RailsA, I need to install rails (and its numerous dependencies) first. But when I want to create ProjectB, I must then switch to using RailsB. Without gemsets, I must do some serious upgrading/downgrading. Not cool.
A possible solution is simply not to worry about what version of rails I use to create the ProjectX folder. If I then use rails 3.0 to create a 3.2 project, I could just manually create the app/assets tree. But that just irks me. Ain't there a better way?
Most people solve this by installing the rails gem first via gem install rails. If you refuse to do that for some reason, you can opt out of the automatic bundling that Rails attempts to do for you. This will work completely regardless of your ruby management system.
mkdir myapp
cd myapp
echo "source :rubygems" > Gemfile
echo "gem 'rails', '3.2.2'" >> Gemfile
bundle install --path vendor/bundle
bundle exec rails new . --skip-bundle
When prompted, type "y" to replace your Gemfile with the default Rails one (or not, as you prefer). Then, once it's done:
bundle install
You're done, and you have boostrapped a new rails app with the version of your choice without installing the rails gem into rubygems.
Suppose you have rails 3.1.0 installed, but you want to create a new project using rails 3.2.13 which is not installed.
Let's say you want the new project to be in ~/projects/Project2.
gem install rails -v 3.2.13
cd ~/projects
rails _3.2.13_ new Project2
This will create the Gemfile for you, locked to the version of rails you specified on the command-line.
I deliberately omitted the idea of keeping a separate copy of gems for the new project, because that goes against the Bundler philosophy, which is to have all gems installed in one place. When you run rails, Bundler will pick the correct gem versions automatically from that central location. That means a project can share gems instead of installing a fresh copy for itself. (Note, however that each version of ruby you install will have its own gems. This is a good thing because native extensions likely won't work across ruby versions.)
You do have to be a bit more aware, because most commands, like rake, will load the newest version of rake that you have installed. You'll need to run bundle exec rake ... to make sure the correct version is loaded. Usually I'll run bundle exec for all commands except rails. You can create an alias to make it shorter (I use bex). To automate this with gem executables, you can use rbenv-binstubs, but you still have to be aware that running non-gem executables like ruby and irb won't automatically use the Gemfile.
Sidenote: rails new will run bundle install, which will check for the newest version of the dependencies. If you want bundler to try to use currently installed gems that satisfy the dependency requirements, you can skip the bundle install with rails new --skip-bundle, then run bundle check in the app dir.
Sidenote 2: suppose you want to use a ruby version for Project2 (e.g. 2.1.8) that's different from the default (e.g. 2.3.0). In that case, running gem install as specified above will install the gems under 2.3.0, which is a waste of time because you'll need to install the gems again under 2.1.8. To solve that problem, you can force the commands to use the preferred version via environment variable:
RBENV_VERSION=2.1.8 gem install rails -v 3.2.13
cd ~/projects
RBENV_VERSION=2.1.8 rails _3.2.13_ new Project2
echo 2.1.8 > Project2/.ruby-version
You could use rbenv shell to set the variable, but I only recommend that if you don't want rbenv to auto-switch based on .ruby-version files for the duration of that shell. It's very easy to forget that you have the variable set, and when you cd to a different project, it won't be using the version you expect.
There's a good recent post on exactly the topic of gemsets / bundler here http://rakeroutes.com/blog/how-to-use-bundler-instead-of-rvm-gemsets/ Good background you can apply to your rbenv setup.

How do RVM and rbenv actually work?

I am interested in how RVM and rbenv actually work.
Obviously they swap between different versions of Ruby and gemsets, but how is this achieved? I had assumed they were simply updating symlinks, but having delved into the code (and I must admit my knowledge of Bash is superficial) they appear to be doing more than this.
Short explanation: rbenv works by hooking into your environment's PATH. The concept is simple, but the devil is in the details; full scoop below.
First, rbenv creates shims for all the commands (ruby, irb, rake, gem and so on) across all your installed versions of Ruby. This process is called rehashing. Every time you install a new version of Ruby or install a gem that provides a command, run rbenv rehash to make sure any new commands are shimmed.
These shims live in a single directory (~/.rbenv/shims by default). To use rbenv, you need only add the shims directory to the front of your PATH:
export PATH="$HOME/.rbenv/shims:$PATH"
Then any time you run ruby from the command line, or run a script whose shebang reads #!/usr/bin/env ruby, your operating system will find ~/.rbenv/shims/ruby first and run it instead of any other ruby executable you may have installed.
Each shim is a tiny Bash script that in turn runs rbenv exec. So with rbenv in your path, irb is equivalent to rbenv exec irb, and ruby -e "puts 42" is equivalent to rbenv exec ruby -e "puts 42".
The rbenv exec command figures out what version of Ruby you want to use, then runs the corresponding command for that version. Here's how:
If the RBENV_VERSION environment variable is set, its value determines the version of Ruby to use.
If the current working directory has an .rbenv-version file, its contents are used to set the RBENV_VERSION environment variable.
If there is no .rbenv-version file in the current directory, rbenv searches each parent directory for an .rbenv-version file until it hits the root of your filesystem. If one is found, its contents are used to set the RBENV_VERSION environment variable.
If RBENV_VERSION is still not set, rbenv tries to set it using the contents of the ~/.rbenv/version file.
If no version is specified anywhere, rbenv assumes you want to use the "system" Ruby—i.e. whatever version would be run if rbenv weren't in your path.
(You can set a project-specific Ruby version with the rbenv local command, which creates a .rbenv-version file in the current directory. Similarly, the rbenv global command modifies the ~/.rbenv/version file.)
Armed with an RBENV_VERSION environment variable, rbenv adds ~/.rbenv/versions/$RBENV_VERSION/bin to the front of your PATH, then execs the command and arguments passed to rbenv exec. Voila!
For a thorough look at exactly what happens under the hood, try setting RBENV_DEBUG=1 and running a Ruby command. Every Bash command that rbenv runs will be written to your terminal.
Now, rbenv is just concerned with switching versions, but a thriving ecosystem of plugins will help you do everything from installing Ruby to setting up your environment, managing "gemsets" and even automating bundle exec.
I am not quite sure what IRC support has to do with switching Ruby versions, and rbenv is designed to be simple and understandable enough not to require support. But should you ever need help, the issue tracker and Twitter are just a couple of clicks away.
Disclosure: I am the author of rbenv, ruby-build, and rbenv-vars.
I wrote an in-depth article: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/
The basic difference is where the shell environment is changed:
RVM: it's changed when you change Ruby.
rbenv: it's changed when you run a Ruby/gem executable.
Also, the thing about RVM is, it covers a lot more then just managing Rubies, it has a lot more than any other tool (there are others apart from RVM and rbenv: https://twitter.com/#!/mpapis/status/171714447910502401)
Do not forget about instant support you get on IRC in the "#rvm" channel on the Freenode servers.
So to summarise the excellent answers above, the main practical difference between RVM and rbenv is when the version of Ruby is selected.
rbenv:
rbenv adds a shim to the start of your path, a command with the same name as Ruby. When you type ruby at a command line the shim is run instead (because it is also called "ruby" and comes first in the path). The shim looks for an environment variable or .rbenv_version file to tell it which version of Ruby to delegate to.
RVM:
RVM allows you to set a version of Ruby directly by calling rvm use. In addition, it also overrides the cd system command. When you cd into a folder that contains a .rvmrc file, the code inside the .rvmrc file is executed. This can be used to set a Ruby version, or anything else you fancy.
Other differences:
There are of course other differences. RVM has gemsets out of the box, while rbenv requires just a little more hacking (but not much). Both are functional solutions to the problem.
The main difference seems to be when and how ruby is switched. Ruby is switched:
for RVM manually (rvm use) or automatically during change of directories
for rbenv automatically each time a ruby command is executed
RVM relies on the modified cd command and manual selection of Ruby by rvm use. rbenv uses wrappers or "shims" for all basic ruby commands as the default mechanism to select ruby. RVM creates wrappers for basic command line tools like gem, rake, ruby, too. They are used for example in CronJobs ( see http://rvm.io/integration/cron/ ), but they are not the default mechanism to switch the Ruby version.
Thus both methods select "automatically" the right Ruby version by overwriting commands and using wrappers. rvm overrides shell commands like cd. rbenv overrides all basic ruby commands such as ruby, irb, rake and gem.
rvm system
env > before
rvm jruby # or whatever
env > after
diff after before
Gives you approximately:
< GEM_HOME=$HOME/.gem/ruby/1.9.1
---
> GEM_HOME=$HOME/.rvm/gems/jruby-1.6.6
< GEM_PATH=$HOME/.gem/ruby/1.9.1
---
> GEM_PATH=$HOME/.rvm/gems/jruby-1.6.6:$HOME/.rvm/gems/jruby-1.6.6#global
*bunch of rvm_*
> MY_RUBY_HOME=$HOME/.rvm/rubies/jruby-1.6.6
> RUBY_VERSION=jruby-1.6.6
> IRBRC=$HOME/.rvm/rubies/jruby-1.6.6/.irbrc
And it prepends:
$HOME/.rvm/gems/jruby-1.6.6/bin:$HOME/.rvm/gems/jruby-1.6.6#global/bin
to $PATH

I have too many versions of Ruby and Rails

I have both ruby and rails installed in:
/usr/local/bin/ruby
/usr/bin/ruby
/usr/local/bin/ruby
This is causing problems when I try to run certains commands like ruby script/console
How do I remove some of these installations of both ruby and rails?
RVM will help you for sure. Check out RVM here
Preventing this kind of situations is the very role of RVM and it's gemsets.
I encourage you to check it out.
There are a few options. First one would be to get your ruby system install in good order. There is no harm in renaming removing those multiple ruby file in your diverse bin folders. Get the stable release of 1.9.2 and gem install whatever you need then. Googling around to fill the gaps you may have here
Quick and dirty you can do:
Get the latest stable release of ruby 1.9.2, compile it on your system, I suppose the ruby that is under /usr/bin is the system's and you are using macosx. The one located in /usr/local/bin is probably something you installed yourself and even maybe you don't even need to reinstall ruby 1.9.2. If that's so get you .bashrc in proper order by making sure /usr/local/bin comes before /usr/bin and you won't have to worry so much about which version you might be using. Create a ~/.bash_profile and put this in.
export PATH="/usr/local/bin:$PATH"
Expected output (more or less):
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/usr/texbin
Others mentioned RVM. I used it, but I don't use it on a production server, I prefer a single sane ruby install to RVM. There is also rbenv and is seems much saner.
Final thought play around in your system remove symlink stuff, set your PATH variable or use RVM/rbenv.
Managing Ruby: Moving From RVM to rbenv
It's time to switch over, http://cantina.co/2011/10/08/managing-ruby-moving-from-rvm-to-rbenv/

Resources