使捆绑器为不同的平台使用不同的宝石

时间:2010-09-04 11:40:56

标签: ruby-on-rails bundler

我正在努力将我们的一个Rails 2.3.8应用程序升级到Rails 3,并且遇到了捆绑和部署的恼人问题。我在Windows机器上开发应用程序,但生产环境正在运行Ubuntu Linux。现在,我的问题是Bundler忽略了生产环境中的mysql gem,并且Passenger吐出:“!!!缺少mysql gem。将它添加到你的Gemfile:gem'mysql',' 2.8.1' “

这是我的Gemfile

# Edit this Gemfile to bundle your application's dependencies.
# This preamble is the current preamble for Rails 3 apps; edit as needed.
source 'http://rubygems.org'

gem 'rails', '3.0.0'
gem 'net-ldap', :require => 'net/ldap'
gem 'highline', :require => 'highline/import'
gem 'mysql', '2.8.1'
gem 'net-ssh', :require => 'net/ssh'

# Bundle gems for the local environment. Make sure to
# put test-only gems in this group so their generators
# and rake tasks are available in development mode:
group :development, :test do
  gem 'fakeweb', :require => 'fakeweb'
  gem 'flexmock', :require => 'flexmock/test_unit'
end

如您所见,指定了mysql gem。但是,在部署时,bundler会忽略它。为什么?原因是Bundler生成以下Gemfile.lock(仅包括相关部分):

....
mime-types (1.16)
mysql (2.8.1-x86-mingw32)
net-ldap (0.1.1)
....

请注意,它包含特定于平台的gem。这显然不是我想要它做的,因为在Linux下运行时,gem不适合(并且显然被忽略)。

那么,Bundler是否有办法解决这些问题?或者每次在开发机器上运行bundle install时,是否必须记得手动更改生成的Gemfile.lock中的mysql gem版本?

提前谢谢!

更新

捆绑团队似乎知道这个issue

11 个答案:

答案 0 :(得分:37)

这是known issue in Bundler。解决方法是:

  • 在类似于您的生产环境的系统上生成Gemfile.lock,以获得与您的生产平台匹配的结果。实际上,这意味着如果您的生产系统是Windows,则只能在Windows上生成Gemfile.lock文件。
  • 根本不提交Gemfile.lock文件,并在部署时确定生产计算机上的依赖关系(bundle install没有--deploy)。虽然一般不推荐,但在修复错误之前,这是一种经常使用的解决方法。例如,这是Heroku提供的推荐解决方案。
  • 切换到JRuby,它在Windows和Linux(java)上具有相同的平台字符串。我不认真对待这个,但我相信它可以解决这个问题。
  • 修复Bundler源代码中的问题,即帮助Bundler团队修复错误。 :)

答案 1 :(得分:8)

我有一个类似的问题。我希望能够在我的Gemfile中写出类似的东西:

platforms :ruby do                      # linux
  gem 'nokogiri', "1.5.0.beta.2" 
end

platforms :mswin do
  gem 'nokogiri', "1.4.4.1" 
end

但是,捆绑者告诉我,我不被允许。因此,我的解决方法,在这个特定情况下工作是指出一系列版本:

gem 'nokogiri', ">= 1.4.4.1", "<=1.5.0.beta.2" 

目前 - 在我的Windows计算机上提供1.4.4.1版本,在我的Linux计算机上提供1.5.0.beta.2。也许你有可能写一个类似的丑陋的解决方法; - )

答案 2 :(得分:5)

我们位于Engine Yard的工程师已经向Bundler提交了一个补丁来解决这个问题,并在不同的平台上解冻宝石。在运行RailsInstaller演示教程之后,许多Windows尝试部署时遇到了同样的问题。我们发现的最佳解决方案是执行以下操作:

  1. bundle install与开发机器上的正常情况一样
  2. 浏览Gemfile.lock,如果有-x86-mingw32行,请删除该部分。
    • bcrypt-ruby (3.0.1-x86-mingw32)变为bcrypt-ruby (3.0.1)
  3. ruby
  4. 的“平台”部分下添加Gemfile.lock
  5. 确保使用平台标志在Gemfile中明确指定所需的gem。 (不确定是否需要,但不会受到伤害)
    • Gemfile:'gem'bcrypt-ruby','〜&gt; 3.0',:platform =&gt; '红宝石'
  6. bundle install再次保留bcrypt-ruby (3.0.1)行并再次添加bcrypt-ruby (3.0.1-x86-mingw32)
  7. 如果您对Bundler补丁感到好奇,可以通过https://github.com/carlhuda/bundler/pull/1451

    收到通知

    希望这有助于任何仍在寻找答案的人。

答案 3 :(得分:2)

我认为问题是mysql gem没有正确发现所需的标头。您可以通过转到使用mysql2 gem来解决此问题,您只需在database.yml中更新数据库适配器以进行ActiveRecord集成。

此外,如果绝对必要,你可以将构建标志传递给C扩展宝石:

bundle config build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config

答案 4 :(得分:2)

之前我遇到过这个问题,使用mysql2 gem确实解决了这个问题。我知道这不是你正在寻找的答案,但将其与Diego的答案结合起来,你就是金色的。

答案 5 :(得分:2)

您是否尝试过使用rvmlink here)?它可以安装独立的Ruby虚拟机和Gemsets,因此您可以使用更像生产环境的环境。老实说,我不知道它是否会解决你的问题,但值得一试。

无论如何,我知道这不是你想听到的答案,但是在Rails中开发时,恕我直言Windows并不是最佳平台。我最近买了一台主要用于开发Rails应用程序的MacBook,它可以让你免于很多麻烦。您也可以在开发计算机上安装Linux并使用它,这比使用Windows端口或Cygwin更好。

答案 6 :(得分:1)

不要将Gemfile.lock和您的宝石提交给制作人员。您必须在生产中再次运行bundler install

答案 7 :(得分:1)

您可以这样做:

platforms :ruby do
  gem "sqlite3-ruby", :require => "sqlite3", :group => [:development, :test]
end

platforms :jruby do
  gem 'activerecord-jdbc-adapter', :require => false
  gem "jdbc-sqlite3", :require => false
end

顺便说一句,您应该将Gemfile.lock放入版本控件中,因为这样所有计算机都将使用相同的gems版本运行应用程序。

答案 8 :(得分:0)

我遇到了这个问题,最后为这个痛苦的任务编写了脚本。 http://gouravtiwari.blogspot.com/2011/03/development-on-windows-deploying-to.html

答案 9 :(得分:0)

我部署到 Linux 用于我们的开发人员临时版本,并部署到 Windows 用于生产和我们的用户临时版本。因此,我需要一个 .lock 文件用于它们(生产和暂存仅使用 .lock 文件,我想确保我使用的是开发人员使用的 gem 版本,这些版本保存在 .lock 文件中)。< /p>

所以我将 Gemfile.lock 的三个版本提交到我的存储库。有正常的 Gemfile.lock。我还为每个不同的平台(_win 和 _linux)创建了锁文件,它们是在该平台上创建的 Gemfile.lock 的副本。

需要额外的一轮提交才能将两个 .lock 文件放入存储库。因此,如果我必须在 Windows 拉取请求后在我的 Mac 上进行捆绑安装,我会将预先存在的 .lock 文件复制为 Windows 版本,并将我的新 .lock 文件复制为 linux 版本。然后我执行拉取请求以更新锁定文件。

在部署时,我用正确的版本覆盖了 Gemfile.lock。

答案 10 :(得分:0)

我为此找到的最佳解决方案是,在本地开发环境和生产环境中使用不同平台的情况下,始终使用 ruby 上的 Gemfile.lock 平台 gem。

您可以通过使用

设置 Bundler 配置值来完成此操作
bundle config set --global force_ruby_platform 'true'

这样,bundle 将始终默认安装 ruby​​ 平台 gem。但这意味着在特定平台上需要本地扩展的所有 gem 都必须编译,因此您需要确保在本地和生产机器上都安装了所需的工具和库。