Here's probably a very "newbieish" question on Bundler, but I'm wondering how bundle install knows what environment to use or how to set it? Or do I even need to? My problem is that I've grouped my gems (in Gemfile) by environments and when deploying now I only want production gems to be installed.
At the top of the application.rb file you can see
# If you have a Gemfile, require the gems listed there, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env) if defined?(Bundler)
When Rails is booted, Bundler automatically loads all the dependencies for the :default group and current environment.
Please note that when you run bundle install, Bundler resolves and install dependencies for all the environments, unless you specify a --without option
$ bundle install --without staging development test
In production, you might also want to add the --deployment flag.
More info about bundle install.
You can use the "group" option in the gem deependency declaration. Check this ASCIICast: http://asciicasts.com/episodes/201-bundler
Related
By some reason some of the developers use a gem and the others don't.
Sometimes I met code like that:
if File.exist?('USE_MY_GEM')
gem 'my_gem'
end
and USE_MY_GEM written in .gitignore. But I believe this is not very good practice.
How to turn a gem off / on for a specific machine?
I would go with Bundler groups feature. This way the Gemfile might contain the group, containing these superfluous gem[s] some developers use.
From the documentation:
Restrict the groups of gems that you want to add to the load path. Only gems in these groups will be require'able:
require 'rubygems'
require 'bundler'
Bundler.setup(:default, :ci)
require 'nokogiri'
Well, the solution was obvious.
We can manage gems in a way we usually manage groups.
Just wrap gem in a group and add --without option:
Gemfile
group :my_gem do
gem 'my_gem'
end
In console:
$ bundle install --without my_gem
Ensure that .gitignore contains:
/.bundle
I'm in China. So I need to change the source to source 'http://ruby.taobao.org/'
But I push it to heroku, and heroku only support source 'https://rubygems.org'
Can I do something like
group :development do
source 'http://ruby.taobao.org/'
end
group :production do
source 'https://rubygems.org'
end
Or what is the corret way of doing this?
Your gem file is correct but you need to change the way you execute the bundler since it doesn't know about Rails and the current environment.
To install in the production environment:
bundle install --without development
To install in the development environment:
bundle install --without production
One way you could do it is to nest certain gems within a source
group :development do
source 'http://ruby.taobao.org/' do
gem1
gem2
end
end
How can I set my Rails environment to development?
According to this question: How do I set my rails 3 app to development mode?, you add ENV['RAILS_ENV'] = 'development' to config/environment.rb.
I did this, but when I try to bundle install, it still tries to install gems for 'production'. I've placed the environment variable line at the start, middle, and end of file.
# Load the Rails application.
require File.expand_path('../application', __FILE__)
# Initialize the Rails application.
Grafly::Application.initialize!
ENV['RAILS_ENV'] = 'development'
This is normal. Bundler is a general-purpose dependency manager for Ruby. It has no idea that Rails exists. The group directives are exposing Bundler's groups feature, not a function of Rails.
If you don't instruct Bundler otherwise, it will install every gem from every group. It doesn't know what groups you do and don't want installed; it just knows that you defined some groups.
If you don't want to install all of your gems (or can't install all of your gems), you can skip production:
bundle install --without production
Similarly, you can skip development and testing gems when you deploy:
bundle install --without development test
(This is how, for example, Heroku and Cloud66 install only the gems you need for production.)
In the rails project I'm working on I inserted support for rspec, cucumber and autotest with this Gemfile (partial)
gem 'rspec-rails'
gem 'cucumber-rails'
gem 'autotest-standalone'
gem 'autotest-rails-pure'
gem 'zentest-without-autotest'
however in order to run tests with autotest i need to execute bundle exec autotest otherwise it fails with this message
$ autotest
loading autotest/cucumber_rails_rspec_rspec2
Error loading Autotest style autotest/cucumber_rails_rspec_rspec2 (no such file to load -- autotest/cucumber_rails_rspec_rspec2). Aborting.
Now I'm developing on a Mac and I'd like to enable autotest-growl and autotest-fsevents gem, but if I insert those lines in my ~/.autotest
require 'autotest/growl'
require 'autotest/fsevent'
then I need to insert the corresponding gems in the Gemfile and everything works, but it breaks builds on my CI server (which is on Linux)
How to solve this without maintaining a different Gemfile for local and CI environments?
EDIT:
For the moment I solved with these lines in Gemfile
if RUBY_PLATFORM.downcase.include?("darwin") # I'm on Mac
gem 'autotest-fsevent'
gem 'autotest-growl'
end
It works both locally and on the CI server, I don't know if it mess something, for the moment it seems to work flawlessly.
Any cleaner way to do that is still welcome.
EDIT2:
I switched to groups solutions. While the previous monkeypatch works pretty well both in development and for continuous integration, it will gives you an error in production if you use capistrano bundler tasks for deployments or if you use bundle install --deployment option (which is advised in production)
When using the if RUBY_PLATFORM.downcase.include?("darwin") line you'll get this error on deploy.
# bundle install --deployment --without development test
You are trying to install in deployment mode after changing
your Gemfile. Run `bundle install` elsewhere and add the
updated Gemfile.lock to version control.
You have deleted from the Gemfile:
* autotest-fsevent
* autotest-growl
So my final solution to this problem is to include platform specific gems in a given group, say osx, and then in production and on CI server exclude it using bundle.
If you use capistrano to deploy put this in your config.rb
set :bundle_without, [:development, :test, :osx]
# capistrano bundler task
require "bundler/capistrano"
You might want to use groups in your gemfile, something like:
group :development do
gem "autotest-growl"
gem "autotest-fsevents"
end
and on the server you use: $ bundle install --without development
You can handle this by taking advantage of the different Gemfile environments (testing, development, production).
Your local box can be development while the CI server is your "production" environment.
With this in mind you can edit your Gemfile to use the appropriate gems depending on the environment.
Edit: Sorry, I think I scanned your post too quickly. But you can add your ~/.autotest to .gitignore so it wont be included on your CI server.
Let's say in a Rails app you have some gems that you use in your app (we'll call them "primary gems") and you have vendored them for portability.
Let's say that those "primary gems" also require gems of their own - we'll call these "secondary gems".
When you are setting up your environment.rb, you have to say:
config.gem 'primary-gem'
for any of the gems you are using directly.
But, do you also need to say . . .
config.gem 'secondary-gem'
even if you are not using that gem explicitly in your app?
Or is it simply enough to include the gem in your vendor/gems directory for it to get picked up by your app?
At deploy time rails knows about your dependencies, so if you want to freeze your gems then you can run
rake gems:unpack:dependencies
to freeze them into the vendor directory.
At runtime however it's the gems job to load it's dependencies, and usually the gems do this, so a config.gem 'primary' should work.
No, you don't or at least you shouldn't. Each GEM specification should include it's own list of dependencies. When primary gem is installed, RubyGems automatically will install each gem dependency on cascade.
In other words, if A requires B that requires C+D, you only need to write
config.gem 'A'
When the command
gem install A
is run, RubyGems will resolve all the dependencies and install them.
You can view all A dependencies running (from a Rails project)
rake gems
Sometimes, a GEM author may forget to include some GEM dependencies in the specification. In this case you should specify them in your environment.rb to force the application to install them. Off course, it's also a good idea to contact the GEM maintainer so that it can fix the problem.