为什么我不需要使用Rails binstub来运行正确的版本?

时间:2018-01-20 17:27:45

标签: ruby-on-rails ruby bundler rbenv

我曾经认为您需要为Rails使用自动生成的binstub才能加载正确的版本,否则您可能会意外加载错误的版本。

但是,我发现无论如何都会加载正确版本的Rails。

考虑以下情况:

# 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

如何加载正确的版本,而不是每次都加载最新版本的Rails?如果工具链足够智能以加载正确版本的Rails,为什么Rails会为自己生成binstub?我对工具链的误解是什么?

(我在这里使用“工具链”这个词,因为我不确定这个魔法在哪里发生:Ruby,Bundler,rbenv或Rails。)

https://github.com/rbenv/rbenv/wiki/Understanding-binstubs

对于上下文,这是从4.2.10开始为Rails自动生成的binstub - 它非常代表Rails 4和5 binstubs看起来像:

#!/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'

1 个答案:

答案 0 :(得分:0)

你实际上在不知情的情况下使用binstub。

让我们来探究一下这是为什么。

首先,从Rails 4应用中删除GemfileGemfile.lock,尝试再次运行rails,然后您会看到此错误:

$ cd foo_app
$ rails --version
Rails 4.2.1
$ rm Gemfile Gemfile.lock
/Users/sean/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.0/lib/bundler/shared_helpers.rb:34:in `default_gemfile': Could not locate Gemfile (Bundler::GemfileNotFound)
    from /Users/sean/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.0/lib/bundler/shared_helpers.rb:39:in `default_lockfile'
    from /Users/sean/.rbenv/versions/2.4.3/lib/ruby/gems/2.4.0/gems/bundler-1.16.0/lib/bundler.rb:318:in `default_lockfile'
    from /Users/sean/Desktop/apps/foo_app/bin/spring:10:in `<top (required)>'
    from bin/rails:3:in `load'
    from bin/rails:3:in `<main>'

令人惊讶的是,即使你没有明确地运行bin/rails,它看起来就像binstubs一样。

现在,重新开始使用干净的Rails 4应用程序,这一次,删除bin文件夹而不是Gemfiles,你会发现你现在正在运行Rails 5:

$ cd .. && rm -rf foo_app && rails _4.2.10_ new foo_app && cd foo_app
$ rails --version
Rails 4.2.1
$ rm -rf bin
$ rails --version
Rails 5.1.4

我不确定这种魔法在哪里发生:Ruby,RubyGems,Bundler,rbenv或Rails - 但你不需要通过它的binstub显式执行Rails,因为它发生在任何一种方式。