#201 Bundler
在本篇中我们将继续关注Rails 3的新特性。这次我们将了解bundler——rails应用中全新的管理gem依赖的方式。
Bundler最近的更新相当的频繁,所以当你准备用它做些什么之前请确保你安装了最新版本。
gem install bundler
可能你注意到了,当我们安装gem的时候我们并没有使用sudo,那是因为我们使用安装在RVM中的一个RUBY版本。
使用Bundler安装Gems
在过去的教程中,当我们试着去启动服务器但是它报出缺少sqlite3-ruby gem的提示,我们一般是手工的使用gem install
安装gem。
gem install sqlite3-ruby
我们可以在应用的Gemfile
里加上sqlite3-ruby,让它变成我们应用的bundler依赖(绑定依赖 bundler也有捆绑 打包的意思)然后就可以用Bundler来替代完成这项工作了。运行bundle install
语句来遍历应用的gem依赖并安装它们。
$ bundle install Fetching source index from http://gemcutter.org Resolving dependencies Installing abstract (1.0.0) from system gems Installing actionmailer (3.0.0.beta) from system gems Installing actionpack (3.0.0.beta) from system gems Installing activemodel (3.0.0.beta) from system gems Installing activerecord (3.0.0.beta) from system gems Installing activeresource (3.0.0.beta) from system gems Installing activesupport (3.0.0.beta) from system gems Installing arel (0.2.1) from rubygems repository at http://gemcutter.org Installing builder (2.1.2) from system gems Installing bundler (0.9.5) from system gems Installing erubis (2.6.5) from system gems Installing i18n (0.3.3) from system gems Installing mail (2.1.2) from system gems Installing memcache-client (1.7.8) from system gems Installing mime-types (1.16) from system gems Installing rack (1.1.0) from system gems Installing rack-mount (0.4.7) from rubygems repository at http://gemcutter.org Installing rack-test (0.5.3) from system gems Installing rails (3.0.0.beta) from system gems Installing railties (3.0.0.beta) from system gems Installing rake (0.8.7) from system gems Installing sqlite3-ruby (1.2.5) from system gems Installing text-format (1.0.0) from system gems Installing text-hyphen (1.0.0) from system gems Installing thor (0.13.1) from rubygems repository at http://gemcutter.org Installing tzinfo (0.3.16) from system gems Your bundle is complete!
我们可以从上面的输出中看到bundler已经安装了所有本应用需要的gem,包括sqlite3-ruby。如果还没有安装Bundler的话可以从Rubygems.com下载并安装。
所以,当你拿不准时,运行bundle install
吧。例如当你新建一个Rails应用或clone别人的应用时你应该这么做,这样你就可以保证你拥有的都是正确的gem。当你部署一个应用的时候你该这么做,这样服务器上装的就都是没问题的gem了。你甚至可以把这句加到你的部署文档(deployment recipe 译注:应该是类似于capistrano的capfile的东东)中去,这样每当你部署的时候它就会运行。
需要特别注意的是不要在运行bundle install
的时候加上sudo
,即使你平时都是用sudo
来安装gem的也不要这么做。
添加Gem依赖
现在我们知道了如何去管理gem,那么我们该如何安装及添加新的gem依赖呢?在之前版本的rails中我们在/config/environment.rb
文件中管理这些依赖,但是到了Rails 3中gem 配置被单独安置到项目根目录下的一个名叫Gemfile
的文件中。初始的Gemfile看起来是这样的:
# Edit this Gemfile to bundle your application's dependencies. source 'http://gemcutter.org' gem "rails", "3.0.0.beta" ## Bundle edge rails: # gem "rails", :git => "git://github.com/rails/rails.git" # ActiveRecord requires a database adapter. By default, # Rails has selected sqlite3. gem "sqlite3-ruby", :require => "sqlite3" ## Bundle the gems you use: # gem "bj" # gem "hpricot", "0.6" # gem "sqlite3-ruby", :require => "sqlite3" # gem "aws-s3", :require => "aws/s3" ## Bundle gems used only in certain environments: # gem "rspec", :group => :test # group :test do # gem "webrat" # end
这个文件中已经包含了几个gem,其中包括rails
和sqlite3-ruby
。可能你已经注意到关于引用到rails gem的那一行包含了版本号。其实在这个文件中引用任何gem都可以指定一个版本号,这样我们就可以引入该gem的某一个特定的版本。如果在某个阶段我们想要升级rails
的版本,在这里修改版本号是比在environment.rb
中修改更好的选择。
如果我们希望在项目中使用其他的gem只需要将它们加到这个文件中。举个例子,我们希望使用will_paginate可以像这样引用它:
gem "will_paginate", ">=2.3.12"
第二个参数是版本号,在这里的意思是让bundler安装2.3.12版或者是能找到的更新的版本。只要我们添加了gem引用我们就能通过bundle install
命令来安装gem,但在我们做那之前先来示范另一个bundle命令:bundle check
。
我们可以运行bundle check
来列出我们的应用需要的但并没有安装的gem。现在如果为我们的项目运行它就会显示出will_paginate gem是项目已经引用但还没有安装的。
$ bundle check The following dependencies are missing * will_paginate (>= 2.3.12, runtime)We can install the missing gems by running bundle install again.
查看其他bundle的可用命令我们运行 bundle help
。
$ bundle help Tasks: bundle check # Checks if the dependencies listed in Gemfile are satisfied by currently installed gems bundle exec # Run the command in context of the bundle bundle help [TASK] # Describe available tasks or one specific task bundle init # Generates a Gemfile into the current working directory bundle install # Install the current environment to the system bundle lock # Locks the bundle to the current set of dependencies, including all child dependencies. bundle pack # Packs all the gems to vendor/cache bundle show # Shows all gems that are part of the bundle. bundle unlock # Unlock the bundle. This allows gem versions to be changed
其他的Gemfile选项
让我们回到Gemfile看看还能在里面写些什么。一个很酷的新特性是能够从一个git仓库中取得gem。举个例子,如果我们希望在我们的项目中使用最新的rails版本我们可以指定rails gem到它的git仓库。
# Bundle edge rails: gem "rails", :git => "git://github.com/rails/rails.git"
这是个非常强大的功能。如果一个gem没有像我们的预期那样工作我们就可以在Github上建立分支、修改代码来满足需求,并且指定gem依赖到我们自己的版本。
我们同样可以为某一环境指定gem。例如我们我们希望使用RSpec测试,那么我们就可以传入:group
选项指定它只在测试环境中安装。
gem "rspec", :group => :test
当有一定量的gem要被指定给某一个环境时可以使用group
并传给他一个block(代码块)。
group :test do gem "webrat" get "rspec" end
如果我们现在运行bundle install
它将会为所有环境装上其所指定的gem。
$ bundle install Fetching source index from http://gemcutter.org Resolving dependencies ... Installing rspec (1.3.0) from rubygems repository at http://gemcutter.org ... Installing webrat (0.7.0) from rubygems repository at http://gemcutter.org Installing will_paginate (2.3.12) from system gems Your bundle is complete!
正如你所看到的,从以上的输出(删节过)中我们可以看到我们指定的两个gem已经安装上了。
如果我们我们希望安装除了某一环境之外指定的gem之外的所有gem,可以使用--without
选项。例如,除了test环境特定的gem都安装我们可以这么做:
bundle install --without=test
当你在安装应用到产品服务器(production server)时并不想装上所有只在测试环境中使用的gem,此时这个功能就派上大用场了。
锁定gem
另一个有用的命令是bundle lock
。这将锁定(你的应用中)用到的gem的特定版本。当我们运行它之后在项目的中会生成一个名叫Gemfile.lock
的新文件。这个文件将列出所有安装的gem及(当前使用的)版本号。当运行过bundle lock
命令后,我们再运行bundle install
命令时安装的gem将是Gemfile.lock
中锁定的版本,即使已有更新的版本可用(也只安装锁定时候的版本)。
你可能在想,什么时候才需要用到bundle lock
。其实,在项目需要被移动的时候这么做都是值得的。如果我们正与其他的Rails开发人员协作开发一个项目,使用bundle lock
将保证开发这个应用时每个人使用的都是相同版本的gem(译注:避免了很多因各自开发环境不同而导致的莫名奇妙的问题)。同样适用的情景还有,当应用即将被部署到服务器时我们希望生产服务器安装的gem版本与开发机器上的完全一样的版本。
如果我们需要在运行了bundle lock
之后更改应用的gem,不要直接更改Gemfile.lock
文件,我们只需要像以前一样的更新Gemfile
文件就行了。因为Gemfile
被锁住了,所以当修改好了Gemfile文件,再运行bundle install
命令时却并不能更新应用的gem。要想更新gem我们需要加上--relock
选项。
bundle install --relock
这一操作将解锁gemfile,升级gem后再重新上锁。
将Gem与应用打包到一起
以上就是bundler的基本工作流程了,足以应付你工作中的绝大部分需要。但我们最后还要了解一个bundler特性,那就是bundle pack
。
Bundler会把gem都安装到我们的home目录下一个叫.bundle
的文件夹中。
$ ls ~/.bundle cache doc gems ruby specifications
那就意味着gem跟我们的应用并不绑定,而且也不被包含在我们项目的版本控制体系里。如果我们希望将gem保存到我们的项目里的话我们就需要运行bundle pack
了。
bundle pack Copying .gem files into vendor/cache * memcache-client-1.7.8.gem * rspec-1.3.0.gem * thor-0.13.3.gem * tzinfo-0.3.16.gem * builder-2.1.2.gem * nokogiri-1.4.1.gem * mime-types-1.16.gem * sqlite3-ruby-1.2.5.gem * i18n-0.3.3.gem * abstract-1.0.0.gem * erubis-2.6.5.gem * text-hyphen-1.0.0.gem * bundler-0.9.6.gem * rake-0.8.7.gem * will_paginate-2.3.12.gem * text-format-1.0.0.gem * rack-1.1.0.gem * rack-test-0.5.3.gem * webrat-0.7.0.gem * rack-mount-0.4.7.gem * activesupport-3.0.0.beta.gem * mail-2.1.2.gem * arel-0.2.1.gem * activemodel-3.0.0.beta.gem * actionpack-3.0.0.beta.gem * actionmailer-3.0.0.beta.gem * activerecord-3.0.0.beta.gem * activeresource-3.0.0.beta.gem * railties-3.0.0.beta.gem * rails-3.0.0.beta.gem
这将生成所有我们应用程序需要的.gem
文件,并将它们拷贝到/vendor/cache
(如果没有这个目录将会创建)下。(以后)这些(被打包的)gem将会直接从这些.gem
文件安装而不再从远端获取,举个例子,Gemcutter。
这将不是一个常用的操作,但是设身处地的想象下如果你不希望生产环境直接连接到Gemcutter去下载gem这就是一个非常好的解决方案了(译注:例如一些重要的内部系统会不允许连接外网,这种打包就非常实用了)。
以上就是我这一集所介绍的了。简单的介绍了如何在你的应用中使用bundler管理gem。Bundler可能是需要费点神来习惯的,但是最终它将保证你远离过去的那些混乱的gem依赖关系的。
最后我鼓励大家用空去railsplugins.org逛逛。可能你正好奇着想知道哪些plugin和gem已经支持了Rails 3,在这里就可以找到答案。在这个网站你就可以查到plugin是否已经支持了Rails 3和Ruby 1.9。
如果在这个网站上发现你即将用在Rails3上的gem是被列为“不支持”或“未经过测试”的,那么这就是个非常好的机会去提问题,或者你也可以帮忙修复它。总之,通过这种方式大家都可以参与其中,好让更多的gem和plugin能与Rails 3协作。
仅提供给英语困难的同学参考用吧,英文好的同学还是直接看原版教程吧。如有错误请发邮件到joey.d.darko@gmail.com