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 安装到 rubygems 中。
【讨论】:
与此解决方案无关,但永远不要编辑您的 .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 可执行文件(如 ruby
和 irb
)不会自动使用 Gemfile。
旁注:rails new
将运行 bundle install
,它将检查最新版本的依赖项。如果您希望 bundler 尝试使用当前安装的满足依赖要求的 gem,您可以跳过 bundle install
和 rails 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.setup
或Bundler.require
在您自己的应用程序中显式加载Gemfile
。【参考方案3】:
最近有一篇关于 gemsets / bundler 主题的好帖子http://rakeroutes.com/blog/how-to-use-bundler-instead-of-rvm-gemsets/ 很好的背景,您可以将其应用于您的 rbenv 设置。
【讨论】:
非常好的文章。如果我知道那个,我就不必发布mine :-)以上是关于rbenv:没有 gemsets 生存的主要内容,如果未能解决你的问题,请参考以下文章