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



我曾经认为你需要使用自动生成的 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 binstub 的样子:

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

您实际上是在不知情的情况下使用垃圾箱存根。

让我们探讨一下为什么会这样。

首先,从 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,看起来垃圾桶也在存在。

现在,从一个干净的 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,因为它正在发生。

最新更新