Are bundle exec and require 'bundler/setup' equivalent?
In your specific example they can be considered the same, however in reality they are not the same.
bundle exec
makes some changes to the environment that bundler/setup
does not make. If your foo.rb
never runs a subshell, or never tries to run other ruby executables in subshells, then both versions are equivalent (they will both load bundled gems correctly and work exactly the same).
The whole idea with bundle exec
is to enable you to run executables that were not originally designed with bundler in mind. Like rspec
, rails
, rackup
. If your own app (foo.rb
) does not try to run such executables that might be dependent on your bundles, then it makes no difference either way. Since all you want to make sure with bundler is that you load the correct gems, and for that bundler/setup
works exactly as expected in your case.
From the bundler docs when talking about running ruby system executables:
In some cases, running executables without bundle exec may work, if the executable happens to be installed in your system and does not pull in any gems that conflict with your bundle.
However, this is unreliable and is the source of considerable pain. Even if it looks like it works, it may not work in the future or on another machine.
Then from the manpage of bundle exec you can get some additional clues as to what bundle exec
actually does:
ENVIRONMENT MODIFICATIONS
- make sure that it's still possible to shell out to bundle from inside a command invoked by bundle exec (using $BUNDLE_BIN_PATH)
- put the directory containing executables (like rails, rspec, rackup) for your bundle on $PATH
- make sure that if bundler is invoked in the subshell, it uses the same Gemfile (by setting BUNDLE_GEMFILE)
- add -rbundler/setup to $RUBYOPT, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle
So if you build your app with bundler support in mind, then you never need to bundle exec
your app.
But if you need to use other tools that load your app code that might load gems before they load your app code (which then might pull in a wrong non-bundled gem), then you need to use bundle exec
.
Why do you need require 'bundler/setup'?
It ensures you're loading Gemfile defined gems. Please have a look at the documentation here https://bundler.io/v1.12/bundler_setup.html
what's the difference between bundle.setup and bundle.require
Bundler.setup
modifies the LOAD_PATH, so you can do things like require 'some_gem'
and they will work. It allows you to require gems 'by hand'. Before Bundler, using Rubygems, you would achieve much of the same effect doing require 'rubygems'
.
Bundler.require(:default)
on the other hand actually requires all the gems in the Gemfile (assuming you're not using groups; otherwise it requires those in the specified groups if you provide arguments). It is a shorthand for a bunch of require 'some_gem'
statements.
See http://gembundler.com/rationale.html. Note that they say you have to do require 'bundler/setup'
before doing Bundler.require
, but in practice this usually is not necessary. I almost never use Bundler.setup
(or require 'bundler/setup
), because I require all gems via Bundler.require
).
Should I use `bundle exec` or Rails' binstubs?
tl;dr no particular difference, but if I were to choose, I'd use bin/rails
There's little to no difference. Let us see.
DISABLE_SPRING=1 bin/rails --version
:
bin/rails
: require_relative '../config/boot'
config/boot
: require 'bundler/setup'
bundler/setup
: Bundler.setup
Bundler.setup
: definition.validate_runtime!
Bundler.definition
: Definition.build
Bundler::Definition.build
: Dsl.evaluate
Bundler::Dsl.evaluate
: builder.eval_gemfile
Bundler::Dsl#eval_gemfile
: instance_eval
After require 'bundler/setup'
, trying to gem 'rails', 'x.y.z'
results in:
*** Gem::LoadError Exception: can't activate rails (= x.y.z), already activated rails-5.1.3. Make sure all dependencies are added to Gemfile.
With bundle exec rails --version
, we end up running bin/rails
anyway:
~/.gem/ruby/x.y.z/bin/rails
: load Gem.activate_bin_path('railties', 'rails', version)
exe/rails
: require 'rails/cli'
rails/cli
: Rails::AppLoader.exec_app
Rails::AppLoader.exec_app
: `exec RUBY, 'bin/rails', *ARGV
Also, do note the message one can found in the last file:
Beginning in Rails 4, Rails ships with a
rails
binstub at ./bin/rails that should be used instead of the Bundler-generatedrails
binstub.
So, at the end of the day there's no difference. But considering the fact that Rails goes through the trouble of shipping its own binstubs, I'd favor bin/rails
alternative. Also, it autocompletes better.
And,
App executables now live in the
bin/
directory:bin/bundle
,bin/rails
,bin/rake
. Runrake rails:update:bin
to add these executables to your own app.script/rails
is gone from new apps.Running executables within your app ensures they use your app's Ruby version and its bundled gems, and it ensures your production deployment tools only need to execute a single script. No more having to carefully
cd
to the app dir and runbundle exec ...
.Rather than treating
bin/
as a junk drawer for generated "binstubs", bundler 1.3 adds support for generating stubs for just the executables you actually use:bundle binstubs unicorn
generatesbin/unicorn
. Add that executable to git and version it just like any other app code.
https://github.com/rails/rails/blob/4-0-stable/railties/CHANGELOG.md
Bundler difference between setup and require?
Google can be your friend. Read this and this.
TL;DR Use Bundler.require instead of Bundler.setup
Run a bundler-deployed Ruby app outside of its own directory?
You use bundler as gem manager for your app. I think in this case using bundle exec
is the best way to run executables.
If you run your app from different directory than directory that contains Gemfile you should set Gemfile location by setting BUNDLE_GEMFILE (see bundle help exec
). Following will help you:
BUNDLE_GEMFILE=/path/to/Gemfile bundle exec /path/to/runmyapp
Related Topics
What Is the Easiest Way I Can Create a 'Beep' Sound from a Ruby Program
Convert Datetime String to Utc in Rails
Creating Categories on Jekyll Driven Site
How to Read the Body Text of an Email Using Ruby's Net/Imap Library
How to Access a Ruby Module Method
Better Way to Turn a Ruby Class into a Module Than Using Refinements
Differencebetween Methods and Attributes in Ruby
Redirect the "Puts" Command Output to a Log File
Rails: Ensure Only One Boolean Field Is Set to True at a Time
Resque Multiple Workers in Development Mode
Best Way to Combine Fragment and Object Caching for Memcached and Rails
How to Delete Specific Characters from a String in Ruby
Converting an Array of Keys and an Array of Values into a Hash in Ruby
Generate Ruby Classes from Xsd
MAC Os X Mountain Lion "Rails Is Not Currently Installed on This System."