rbenv:没有宝石的幸存

时间:2012-03-19 13:34:58

标签: ruby-on-rails ruby rubygems bundler rbenv

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的单个版本,因此需要gemsets来隔离命名空间。不对。可以同时安装多个版本的gem。从命令行调用时将使用最新的一个,除非您有一个指定版本约束的Gemfile并通过bundle exec调用该命令,或者将该版本指定为其第一个参数。

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


原始问题:

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

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

USE CASE:我有两个rails项目,名为ProjectA和ProjectB。 ProjectA是使用一个版本的rails(“RailsA”)开发的,而ProjectB使用不同的版本(“RailsB”)。如何安装两个版本?

GEMSETS方法:当我第一次开始使用Rails开发时,我使用了RVM。除了支持多个并发安装的ruby之外,RVM还支持多个Named Gem Sets。每个项目都有自己独立的宝石集合(包括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命令使用所需的版本来完成(恕我直言),因为骨架文件从版本更改为版本。 (也许我应该重温这个前提?)

BUNDLER方法:我一直在使用rbenv而不是RVM,但我并不清楚工作流程。在README.md中,Sam Stephenson写道“rbenv不管理gemsets .Bundler是管理应用程序依赖性的更好方法。”有一个插件(rbenv-gemset)用于获得与rvm的gemsets相同的结果,但Sam显然倾向于使用Bundler。不幸的是,他没有详细说明工作流程的样子。甚至Bundler网站也没有明确地将如何将一个项目与另一个项目隔离开来。有几个blogs and gists来救援,建议使用以下~/.bundle/config文件:

---
BUNDLE_PATH: vendor/bundle
(顺便说一句,顺便说一下,我不确定“---”是什么。文档没有提及它,它似乎没有什么区别。)

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

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

一个可能的解决方案就是不用担心我用来创建ProjectX文件夹的rails版本。如果我然后使用rails 3.0创建一个3.2项目,我可以手动创建app / assets树。但那只会让我感到烦恼。是不是有更好的方法?

3 个答案:

答案 0 :(得分:42)

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

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中。

答案 1 :(得分:12)

假设您已安装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版本。

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

您必须要更加清楚,因为大多数命令(如rake)都会加载您安装的最新版rake。您需要运行bundle exec rake ...以确保加载了正确的版本。通常我会为bundle exec以外的所有命令运行rails。您可以创建别名以缩短它(我使用bex)。要使用gem可执行文件自动执行此操作,您可以使用rbenv-binstubs,但仍需要注意运行非rubyirb等非gem可执行文件不会自动使用Gemfile。< / p>

Sidenote rails new将运行bundle install,它将检查最新版本的依赖项。如果您希望bundler尝试使用满足依赖性要求的当前安装的gem,则可以使用bundle install跳过rails new --skip-bundle,然后在app dir中运行bundle check

Sidenote 2 :假设您要使用与默认值不同的Project2(例如2.1.8)的ruby版本(例如2.3.0)。在这种情况下,如上所述运行gem install将在2.3.0下安装宝石,这是浪费时间,因为您需要在2.1.8下再次安装宝石。要解决该问题,可以强制命令通过环境变量使用首选版本:

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在此期间基于.ruby-version文件自动切换那个壳。很容易忘记你有变量集,当你cd到另一个项目时,它将不会使用你期望的版本。

答案 2 :(得分:8)

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