rbenv:没有 gemsets 生存

Posted

技术标签:

【中文标题】rbenv:没有 gemsets 生存【英文标题】:rbenv: Surviving without gemsets 【发布时间】:2012-04-03 23:56:25 【问题描述】:

TL;DR

不要为宝石而烦恼;可以同时安装多个版本的 gem。 必要时,使用$ gem-based-binary _version_ args 表示法指定要执行的版本。 当您有指定版本的 Gemfile 时使用 bundle exec
gem install rails -v 3.2.13
rails _3.2.13_ new Project2
cd Project2
bundle exec rails server

更新: 2015-06-04

我三年前写了这个问题。部分原因是基于错误的假设,部分情况从那时起发生了变化。感谢@indirect 的原始答案,我想提请注意@kelvin 的更新(较少赞成)答案,总结在上面。

我的错误假设:一次只能安装一个 gem 版本,因此需要 gemset 来隔离命名空间。不对。可以同时安装多个版本的 gem。从命令行调用时将使用最新的,除非您有一个 Gemfile 指定版本约束并通过 bundle exec 调用命令,或者将版本指定为其第一个参数。

另请参阅How can I call an older version of a gem from the commandline? re:下划线版本表示法。


原问题:

我有多个项目正在使用不同版本的 Rails。我有一个工作流程(如下所述),用于使用特定版本的 rails 创建项目,并使项目彼此隔离。我想尝试其他工作流程,特别是使用 rbenv 而不是 RVM,但不清楚如何去做。

问题:在使用 rbenv时,创建多个 rails 项目(每个项目使用不同版本的 rails)的当前最佳实践是什么? > 和 bundler,而不是 rbenv-gemset 或 rvm?

用例:我有两个 Rails 项目,分别称为 ProjectA 和 ProjectB。 ProjectA 是使用一个版本的 rails(“RailsA”)开发的,而 ProjectB 使用不同的版本(“RailsB”)。如何管理同时安装这两个版本?

GEMSETS 方法:当我第一次开始使用 Rails 开发时,我使用了RVM。除了支持 ruby​​ 的多个并发安装之外,RVM 还支持多个Named Gem Sets。每个项目都有自己独立的 gems 集合(包括 rails 本身),称为 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

注意:项目文件夹的创建应该通过rails new命令使用所需版本的rails来完成(恕我直言),因为骨架文件发生了变化从版本到版本。 (也许我应该重新审视这个前提?)

捆绑器方法:我一直在尝试使用 rbenv 而不是 RVM,但我不太清楚工作流程。在README.md 中,Sam Stephenson 写道:“rbenv 不......管理 gemset。Bundler 是管理应用程序依赖项的更好方法。”有一个插件 (rbenv-gemset) 可以获得与 rvm 的 gemsets 相同的结果,但 Sam 显然更喜欢使用 Bundler。不幸的是,他没有详细说明工作流程会是什么样子。甚至Bundler 网站也没有明确连接如何将一个项目与另一个项目隔离开来。几位blogsandgists前来救援,提示以下~/.bundle/config文件:

---
BUNDLE_PATH: vendor/bundle

(顺便说一句,我不确定“---”是什么意思。文档没有提到它,而且似乎没有什么区别。)

这有效地为每个 Rails 项目提供了自己的 gemset,将 gem 存储在 ProjectX/vendor/bundle/ 中。事实上,一旦我运行bundle install,rails 本身就会(重新)安装在那里,使项目完全独立于我的环境的其余部分。

但是房间里的大象是首先创建rails项目文件夹的先有鸡还是先有蛋的问题!!为了使用 RailsA 创建 ProjectA 文件夹,我需要安装 rails(及其众多依赖项)首先。但是当我想创建 ProjectB 时,我必须切换到使用 RailsB。如果没有 gemset,我必须进行一些认真的升级/降级。不酷。

一个可能的解决方案就是不用担心我使用什么版本的 rails 来创建 ProjectX 文件夹。如果我然后使用 rails 3.0 创建一个 3.2 项目,我可以手动创建应用程序/资产树。但这让我很恼火。没有更好的办法吗?

【问题讨论】:

听起来你真的很想使用 RVM 和 gemsets。您选择不使用最优雅地解决您的问题的工具有什么特别的原因吗? 我不致力于任何特定的工具(而且我绝对不想进入“RVM 与 rbenv”的讨论)。我更熟悉 RVM,并且了解使用它的工作流程。我想了解 rbenv 的等效工作流程,如果没有别的,只是为了能熟练使用各种工具。 你说 Bundler 的网站没有解释如何“将一个项目与另一个项目隔离开来”。如果“隔离”意味着每个项目都有一个完全相同的 gem 和版本的单独副本(例如 rack-1.4.0),那么 Bundler 不会这样做。它在磁盘上维护每个 gem 的单个副本 - 任何需要该 gem 和版本的应用程序都可以使用它而不会干扰其他应用程序。这就像运行 2 个 bash 实例;您在磁盘上没有bash 的多个副本,但在内存中有多个副本。 Gemsets 让您在磁盘上有多个副本(当不再需要时可能更容易删除) 相关:How do you use multiple rails versions with rbenv?. "---" 是 YAML 工件。用 YAML 格式生成的输出会有这个,但解析文件不需要。 【参考方案1】:

大多数人首先通过gem install rails 安装rails gem 来解决这个问题。如果您出于某种原因拒绝这样做,您可以选择退出 Rails 尝试为您执行的自动捆绑。无论您的红宝石管理系统如何,这都将完全有效。

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

当出现提示时,输入“y”将您的 Gemfile 替换为默认的 Rails 文件(或不替换,根据您的喜好)。然后,一旦完成:

bundle install

您已经完成了,您已经使用您选择的版本启动了一个新的 rails 应用程序,而无需将 rails gem 安装到 ruby​​gems 中。

【讨论】:

与此解决方案无关,但永远不要编辑您的 .bundle/config 文件。如果要隔离项目的 gem,请使用 bundle install --path vendor/bundle 谢谢,间接的!您能否详细说明您的评论? ~/.bundle/config 方法有什么问题?为什么使用 --path 更好? 作为记录,更新的 Rails 版本在完成 rails new 时会自动运行 bundle install(3.2.2 会这样做;3.0.12 不会。不确定添加的确切时间。 ) 但是,捆绑安装在自动运行时会失败。 --skip-bundle 跳过这一步。当你手动运行它时它会起作用。 ~/.bundle/config 是 Bundler 的内部实现细节。我们用它来记住传递给安装的标志,比如--path vendor/bundle。你不应该自己编辑它,因为如果你这样做可能会发生不受支持的事情。 :) 三连字符是因为它存储为 YAML 文件。我特别建议 ​​--skip-bundle 以便跳过 bundle install 的失败自动运行。我相信它失败是因为这些命令如何引导 rails gem。 现在您可以拨打rails _3.1.2_ new ...blablabla...【参考方案2】:

假设您安装了 rails 3.1.0,但您想使用未安装的 rails 3.2.13 创建一个新项目。

假设您希望新项目位于~/projects/Project2

gem install rails -v 3.2.13
cd ~/projects
rails _3.2.13_ new Project2

这将为您创建Gemfile,锁定到您在命令行中指定的rails 版本。

我故意省略了为新项目保留单独的 gem 副本的想法,因为这违背了 Bundler 的理念,即将所有的 gem 安装在一个地方。当您运行 rails 时,Bundler 会自动从该中心位置选择正确的 gem 版本。这意味着一个项目可以共享 gem,而不是为自己安装一个新的副本。 (但是请注意,您安装的每个 ruby​​ 版本都会有自己的 gem。这是一件好事,因为本机扩展可能无法跨 ruby​​ 版本运行。)

您必须更加注意,因为大多数命令,例如rake,将加载您已安装的最新版本的rake。您需要运行bundle exec rake ... 以确保加载了正确的版本。通常我会为除rails 之外的所有命令运行bundle exec。您可以创建一个别名以使其更短(我使用bex)。要使用 gem 可执行文件自动执行此操作,您可以使用 rbenv-binstubs,但您仍然需要注意,运行非 gem 可执行文件(如 rubyirb)不会自动使用 Gemfile。

旁注rails new 将运行 bundle install,它将检查最新版本的依赖项。如果您希望 bundler 尝试使用当前安装的满足依赖要求的 gem,您可以跳过 bundle installrails new --skip-bundle,然后在应用程序目录中运行 bundle check

旁注 2:假设您想为 Project2 使用不同于默认(例如 2.3.0)的 ruby​​ 版本(例如 2.1.8)。在这种情况下,按照上面的说明运行gem install 会在 2.3.0 下安装 gem,这是浪费时间,因为您需要在 2.1.8 下再次安装 gem。要解决这个问题,您可以通过环境变量强制命令使用首选版本:

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

可以使用rbenv shell 来设置变量,但我只建议您不希望rbenv 在该shell 期间基于.ruby-version 文件自动切换。很容易忘记您已经设置了变量,并且当您 cd 到不同的项目时,它不会使用您期望的版本。

【讨论】:

re:旁注 2:我想我很容易忘记变量名并必须查找它。不值得花时间。最好打开一个新窗口以进行快速rbenv shell 会话,然后立即关闭。就个人而言,这对我来说更容易记住。 YMMV。此外,如果您将bundle exec 用于所有 命令,包括 rails,如果您忘记运行rbenv shell 并进入另一个项目文件夹。 您不使用 Bundler 启动 Rails 的理由是什么。 (回复:“通常我会为除 rails 之外的所有命令运行 bundle exec”) n.b.我沉迷于一些别名: alias be='bundle exec' ;别名 brs='be rails server' ; alias brc='be rails console' ; @NoachMagedman 回复:不使用捆绑程序启动 rails - 我不这样做是因为 rails 可执行文件自动使用 Gemfile (当然,无论如何预先添加 bundle exec 也无妨,但是就个人而言,我懒得打字,但显然不是懒得记住何时使用它)。顺便说一句,Rails 没有使用黑魔法。您可以使用Bundler.setupBundler.require 在您自己的应用程序中显式加载Gemfile【参考方案3】:

最近有一篇关于 gemsets / bundler 主题的好帖子http://rakeroutes.com/blog/how-to-use-bundler-instead-of-rvm-gemsets/ 很好的背景,您可以将其应用于您的 rbenv 设置。

【讨论】:

非常好的文章。如果我知道那个,我就不必发布mine :-)

以上是关于rbenv:没有 gemsets 生存的主要内容,如果未能解决你的问题,请参考以下文章

生存曲线(三):统计分析方法这么多,到底选哪个?

OO生存指.....抱歉无法生存

linux终端下生存30天

生存的意义

Redis整理第三波(生存时间事务管理)

生存无法识别右删失数据