I'm working on upgrading one of our Rails 2.3.8 apps to Rails 3, and have run into an annoying problem with bundler and deployment. I develop the application on a Windows machine, but the production environment is running Ubuntu Linux. Now, my problem is that bundler is ignoring the mysql
gem in the production environment, and Passenger spits out: "!!! Missing the mysql gem. Add it to your Gemfile: gem 'mysql', '2.8.1'"
Here is my 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 =&g开发者_JS百科t; 'fakeweb'
gem 'flexmock', :require => 'flexmock/test_unit'
end
As you can see, the mysql
gem is specified. However, when deploying, bundler ignores it. Why? The reason is that Bundler generates the following Gemfile.lock
(only relevant parts included):
....
mime-types (1.16)
mysql (2.8.1-x86-mingw32)
net-ldap (0.1.1)
....
Notice that it includes the platform specific gem. This is obviously NOT what I want it to do, as that gem is not suitable (and appearently ignored) when running under Linux.
So, does Bundler come with any way to deal with these issues? Or do I have to remember to manually change the mysql gem version in the generated Gemfile.lock
every time I run bundle install on my development machine?
Thank you in advance!
Update
It seems like the bundler team is aware of this issue.
This is a known issue in Bundler. The workarounds are either:
- Generate a Gemfile.lock on a system similar enough to your production environment that you get results that match your production platform. Effectively, that means you can only generate the Gemfile.lock file on Windows if your production system is Windows.
- Don't commit a Gemfile.lock file at all, and determine dependencies on the production machine at deploy time (
bundle install
without--deploy
). While not recommended in general, this is an often-used workaround until the bug is fixed. For example, this is the recommended solution offered by Heroku. - Switch to JRuby, which would have the same platform string across both Windows and Linux (
java
). I don't recommend this seriously, but I believe it would fix the problem. - Fix the problem in the Bundler source code, i.e., help the Bundler team fix the bug. :)
I have a similiar problem. I would like to be able to write something like this in my Gemfile:
platforms :ruby do # linux
gem 'nokogiri', "1.5.0.beta.2"
end
platforms :mswin do
gem 'nokogiri', "1.4.4.1"
end
But, bundler tells me I am not allowed. So, my workaround, that works in this specific case is to point out a range of versions:
gem 'nokogiri', ">= 1.4.4.1", "<=1.5.0.beta.2"
Which - at the moment - give the 1.4.4.1 version on my Windows computer and 1.5.0.beta.2 on my linux computer. Maybe it is possible for you to write a similiar ugly workaround ;-)
Our engineers at Engine Yard have submitted a patch to Bundler to address this issue and unfreeze the gems if on a different platform. We've been having the same problem with many Windows trying to deploy after running through the RailsInstaller Demo Tutorial. The best fix we've found is to perform the following:
bundle install
like normal on your development machine- Go through the
Gemfile.lock
and if there are any lines with-x86-mingw32
, remove that part.bcrypt-ruby (3.0.1-x86-mingw32)
becomesbcrypt-ruby (3.0.1)
- Add
ruby
under the 'Platforms' section in theGemfile.lock
- Make sure to explicitly specify the needed gem in the
Gemfile
with the platform flag. (Not sure if this is needed but it doesn't hurt)- In
Gemfile
: `gem 'bcrypt-ruby', '~> 3.0', :platform => 'ruby'
- In
bundle install
again which will keep thebcrypt-ruby (3.0.1)
line and add inbcrypt-ruby (3.0.1-x86-mingw32)
again.
If you're curious about the Bundler patch, you can get notifications at https://github.com/carlhuda/bundler/pull/1451
Hope this helps anyone still looking for answers.
I think the issue is that the mysql gem doesn't properly discover the needed headers. You can fix this by moving over to using the mysql2 gem, you'll just have to update your database adapters in database.yml
for ActiveRecord integration.
Additionally, you can pass build flags to C extending gems if absolutely necessary:
bundle config build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config
.
I've ran into this issue before, and using the mysql2 gem does indeed fix the problem. I know that's not the answer you're looking for, but combine that with Diego's answer and you're golden.
Have you tried using rvm
(link here)? It can install isolated Ruby Virtual Machines and Gemsets, so you can work with an environment more like the one you have in production. I honestly don't know if it will solve your problems, but it's worth a shot.
Anyway, I know this is not the answer you want to hear, but IMHO Windows is not the best platform use when developing in Rails. I recently bought a MacBook mainly to develop Rails applications, it saves you from a lot of headaches. You can also install Linux on your development machine and use it, it's way better than using Windows ports or Cygwin.
Don't commit Gemfile.lock
and your gems to production. You have to run bundler install
again in production.
You can do something like this:
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
Btw, you should put your Gemfile.lock into the version control because this way all machines will run the application with the same gems versions.
I came across this issue and then ended up writing script for this painful task. http://gouravtiwari.blogspot.com/2011/03/development-on-windows-deploying-to.html
I deploy to Linux for our developers staging version, and to Windows for production and our users staging version. Thus I need a .lock file for both of them (production and staging only use the .lock file, and I want to be sure that I am using the gem versions used by the developers which are kept in the .lock file).
So I have three versions of my Gemfile.lock committed to my repository. There is the normal Gemfile.lock. I also create lock files for each different platforms (_win and _linux), which are a copy of the Gemfile.lock created on that platform.
It takes an extra round of commits to get both of the .lock files into the repo. Thus if I have to do a bundle install on my Mac after a windows pull request, I copy the pre-existing .lock file as the windows version, and copy my new .lock file as the linux version. I then do a pull request to update the lock files.
When Deploying, I overwrite the Gemfile.lock with the correct version.
The best solution I've found for this, where you have different platforms for your local development environment and for production is to always use the ruby
platform gems on the Gemfile.lock
.
You can accomplish this by setting the Bundler config value with
bundle config set --global force_ruby_platform 'true'
That way the bundle will always default to install the ruby platform gems. But this implies that all gems that need native extensions on a specific platform will have to be compiled, so you need to get sure you have the required tools and libraries installed on both your local and production machines.
精彩评论