I used to think that you needed to use the automatically-generated binstub for Rails in order to load the correct version, otherwise you might accidentally load the wrong version.
However, I’ve found that the correct version of Rails is loaded regardless.
Consider the following scenario:
# System context
$ ruby --version
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]
$ which ruby
/Users/sean/.rbenv/shims/ruby
$ rbenv versions
system
* 2.4.3 (set by /Users/sean/.rbenv/version)
# Install three different versions of Rails
$ gem install rails
$ gem install rails -v 4.2.10
$ gem install rails -v 3.2.22.5
$ gem list | grep rails
rails (5.1.4, 4.2.10, 3.2.22.5)
# Globally, I’m using Rails 5.1.4
$ rails --version
# Creating a new app using Rails 4.2.1
$ rails _4.2.10_ new foo_app
$ cd foo_app
$ which rails
/Users/sean/.rbenv/shims/rails
$ rails --version
Rails 4.2.1
# Creating a new app using Rails 3.2.22.5
$ rails _3.2.22.5_ new bar_app
$ cd bar_app
$ which rails
/Users/sean/.rbenv/shims/rails
$ rails --version
Rails 3.2.22.5
How is the correct version being loaded, instead of the most recent version of Rails every time? If the toolchain is smart enough to load the correct version of Rails, why does Rails generate a binstub for itself? What am I misunderstanding about the toolchain?
(I’m using the word "toolchain" here because I'm not sure where this magic is happening: Ruby, Bundler, rbenv, or Rails.)
https://github.com/rbenv/rbenv/wiki/Understanding-binstubs
For context, this is the automatically generated binstub for Rails from version 4.2.10 — it’s pretty representative of Rails 4 and 5 binstubs look like:
#!/usr/bin/env ruby
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'