What's inside my rails ./bin directory? - ruby-on-rails

Ruby on Rails 4 introduced* the ./bin directory. Inside of ./bin are a few executables: bundle, rails, rake, setup, spring.
My questions are:
What do these executables do? Why do they exist?
When are they invoked?
Can I edit them? Why would I edit them?
I've read the source of these files, and I've tried to Google their purpose, but I can't wrap my head around it. I'm looking for an in-depth explanation.
*I believe many of these files existed before Rails 4, just in different location.

Introduced in Rails 4, the ./bin directory contains your app's "binstubs." Binstubs are wrappers around gem executables, like rails or bundle, which ensures a gem executable is run inside the correct environment for your Rails app.
Binstubs can be used in lieu of bundle exec to run a gem's executable inside your app's environment. For example, instead of typing bundle exec rails scaffold products you can type bin/rails scaffold products. Using binstubs is more flexible than bundle exec, because you don't have to cd to the app's root directory and type bundle exec before everything.
By default, bundle, rails, rake, setup, spring binstubs are created automatically for new rails projects. To make a binstub for a gem executable, just type bundle binstubs name_of_gem_executable. You'll find the new binstub in your ./bin directory.
Some suggest putting ./bin in your shell's search $PATH, so that you don't have to type bin/rails and you can just type rails. This is risky because it depends on ./bin coming before the gem executable's path in $PATH; if you happen to forget this ordering and adjust $PATH such that the gem's executable is found before the binstub wrapper, you could easily invoke the gem's executable -- sans the environmental pretext -- without realizing it.

A bin (short for binary) is nothing more than an application. As you have noticed, these files are ruby files, but they do not have the .rb extension and can be run from your shell just as any shell command, without the need to start any ruby interpreter yourself.
So what do theses programs do? I'm pretty sure you know already what rails rake bundle do.
About spring, it's a gem that keeps your app running in the background (hence its need to be run independently from the app). More infos on their github.
I see no reason to edit these files, but that being said, they're ruby files so you can do whatever you want with them. One example of why you may want editing can be found here.
I personally do put some stuffs in the bin folder. Scripts to connect to remote servers, or ruby scripts I need but that I don't want to run as rake tasks since they're more general than my application.

Related

Bundler is using a binstub that was created for a different gem.

When I run a rails console using
rails console
everything is fine.
When I run a rails console using
bundle exec rails console
I get the following warning
Bundler is using a binstub that was created for a different gem.
This is deprecated, in future versions you may need to `bundle binstub my_gem` to work around a system/bundle conflict.
my_gem happens to be a gem that I've created that is completely unrelated and not used in the current project directory.
I've tried every solution in this question with no luck:
Bundler is using a binstub that was created for a different gem
I would appreciate any guidance on removing this warning or help understanding how binstubs work so that I can figure out what's going on.
Nowadays it's common for projects to have "specialized" versions of tools. E.g. in some projects the "rails" command may be expected to be run using "spring" (to start up faster).
So it's not uncommon to generate files in your project's 'bin' directory, and then use those versions when running commands, so e.g. instead of
bundle exec rails console
or
bundle exec spring rails console
you could simply expect the following to work correctly
bin/rails console
and not care whether the project needs spring or bundler or zeus or whatever.
So if you don't have 'bin/rails' in your project, you should generate one that suits the project, e.g. using
bin/rake rails:update:bin
If you don't already have bin/rake, you might have to use
bundle exec rake rails:update:bin
(so your bin/rake commands will also get a speedup from using spring)
Some people even put ./bin in their paths, so whenever they run rake (or whatever) they are actually running ./bin/rake if it exists.
Troubleshooting
for project specific tasks, use bin/* files, creating them if needed (e.g. using special rake tasks like in Rails or using bundle binstub <gemname>) - usually those have Bundler specific lines that will make Bundler happy.
for non-project gems (like your gem), find out where it is (e.g. which mygem) and check out it's contents - it's probably using e.g. "bundler/setup" which is confusing Bundler (because bundler expects a local Gemfile file). Maybe your gem is using bundler (it shouldn't if it's a "global" kind of tool and not a "project" tool).
Also, if you're using them, check if tools like RVM and .rbenv are correctly adding their stuff to your bin files (they usually need to setup specific paths)
If you still have questions, it's best to post the contents of the bin file causing problems - it's meant to be a plain Ruby file, so if there's something wrong, it's usually because of the file contents (and not anything else).
More info: https://github.com/sstephenson/rbenv/wiki/Understanding-binstubs
It happened in a project of mine. Because I ran bundle install with another ruby version.
Make sure your rvm is the correctly ruby version.

What adds bin dir of a rails app?

I can run rails with bundle exec rails, can't I? What's the difference between this and bin/rails then? There's also bundler's binstubs feature, which makes things even more complex. Briefly, which way should I run executables of a rails app, and why?
https://github.com/sstephenson/rbenv/wiki/Understanding-binstubs
Preface, emphasises mine:
When you run rspec within your project’s directory, rbenv can ensure that it will get executed with the Ruby version configured for that project. However, nothing will ensure that the right version of RSpec gets activated; in fact, RubyGems will simply activate the latest RSpec version even if your project depends on an older version. In the context of a project, this is unwanted behavior.
This is why bundle exec is so essential. It ensures the right versions of dependencies get activated, ensuring a consistent ruby runtime environment. However, it's a pain to always have to write bundle exec.
To answer your question:
"I can run rails with bundle exec rails, can't I? What's the difference between this and bin/rails then?"
(from the same guide)
bundle exec is so often needed. It ensures the right versions of dependencies get activated, ensuring a consistent ruby runtime environment. However, bundle exec is a pain to always have to write.
This is where "bundlers binstubs feature" comes in:
Bundler can install binstubs for executables contained in your project's bundle:
bundle install --binstubs
RSpec can now be easily run with just bin/rspec
"which way should I run executables of a rails app, and why?"
You are encouraged to check these binstubs in the project's version control so your colleagues might benefit from them.

difference between running rake command with and without bundle exec

What is the major difference between running the rake command with and without bundle exec?
I have seen few posts stated that when you run the command with bundle exec then it will be run on scope of the gems version defined in the gem file. If that is the case, then it should be mandatory to run rake command with bundle exec?
bundle exec rake some:task runs the rake task within the context of your bundle.
You didn't explicitly mention Rails but i see you're post is tagged with Rails so a contrived example of this in action might be the following:
You have version 2.0 of the fictitious whateva-whateva gem installed on your system for some valid reason.
You decide you want to pull down an old Rails project from somewhere to check it out and run bundle install within the cloned project's root folder. That command will install all of the gems that the Rails app requires and one of them happens to be verison 1.0 of the fictitious whateva-whateva gem.
So the current state is this: your old rails app has a gem bundle that includes an older version of the whateva-whateva and your systemwide gems include a newer version of the whateva-whateva gem.
When you run rake tasks associated with your Rails app, which version do you want loaded? The older one of course.
In order to do this you can use bundle exec rake the:task and it runs the rake command within the context of your bundle -- the older version of the gem plus whatever other stuff was specified in the old rails app's Gemfile.
So yeah after all that, i think it's safe to say that BEST practice would be that you should always prepend bundle exec but to be honest I'm pretty lazy and rarely do it unless I see problems.
In other news, if you use Bundler's binstubs you don't need to add it. Here's a link to setting that up: https://thoughtbot.com/blog/use-bundlers-binstubs
BUNDLE_GEMFILE=/path/to/gemfile bundle exec can be used to precede any command (if BUNDLE_GEMFILE is not specified it searches up the file system and uses the first one it finds), not just rake.
Any command you run may invoke executable Ruby commands (such as rake) or require code from Ruby libraries (such as the Rake::Task class), and these things are typically provided by gems. gem env tells you where the gem-provided libraries and executables are. However if you use bundle exec it restricts the available gems to those specified in the Gemfile.lock file associated with the Gemfile your bundle exec context is using.
Using all the available gems on your machine (which can happen if you don't do bundle exec) can be undesirable for a couple reasons:
You may have incompatibilities in your full gem set.
It's harder to tell exactly what gems you're using, adding some unpredictability to your working environment.
Here's a quick way to see the difference.
gem install thin
Create a directory foo with two files: an empty Gemfile and a file foo.rb with the contents:
#! /usr/bin/ruby (or whatever the path to your system Ruby is)
require 'thin'
Make foo.rb executable.
Note that running thin and ./foo.rb from the command line both work, but preceding either with bundle exec will not work.
If you use bundle exec before any command in rails, It will search for the Gems Which are mentioned in our Gemfile, in application home folder.
Suppose, You have 2 applications, and using different ruby versions for each of them.
Without bundle exec the command might be failed to run, as it may take different version Gem to run that task. But If you start using bundle exec It will take the exact gem version to run the task/application.
I recommend you to use **bundle exec** before any command.
bundle-exec - Execute a command in the context of the bundle
This command executes the command, making all gems specified in the Gemfile(5) available to require in Ruby programs.
It's not for the only rake, instead applicable for rails, rspec, rackup command too.
Essentially, if you would have normally run something like rspec spec/my_spec.rb, and you want to use the gems specified in the Gemfile(5) and installed via bundle install(1), you should run bundle exec rspec spec/my_spec.rb.
Note that bundle exec does not require that an executable is available on your shell's $PATH.
For more detail, have a look to bundle exec doc.

Call a rubygem's binary executable from inside my rails applications?

I know that bundler makes a gems executables available using the bundle exec command. I want to understand how I can call these executables from inside a controller action or model class method? I don't see anything about this in the Bundler doco.
Executables are ruby scripts sitting in the bin directory of the gems and their behavior depend on each gem. They are wrappers around the gems classes/APIs: simply dig into the source code of the gems you target and mimic the behavior of their CLIs.

Files added to my Ruby Project when using RBENV

After installing RBEnv and rebuilding my ROR project, I now seem to have added many, many files to my project. They are in /vendor/local, and appear to duplicate what you would normally find in /Library/Ruby/Gems.
My project will not run without these files present (I get the message Could not find rake-0.9.2.2 in any of the sources.
I had difficulties with my RBEnv installation. I have what I suspect are other issues (like I have to bundle exec rails instead of just running rails). I suspect that I have done something wrong and should not have these files in my project. What I'd like to know is:
1) Should these files be there?
2) How best to fix this (if this is not how it is supposed to work)?
3) If the best approach is to start over and reinstall rbenv, how do I clear it all out?
It is true that using RBENV will end up putting copies of your gems in the project's /vendor/local folder. This is to remove any dependencies on your base gem set. These files need not be part of your source repository, as long as your 'gemfile' and your '.rbenv-version' file are included in the repository.
Another price you pay for using rbenv is that you must bundle exec rails <command> and bundle exec rake <command> from here on in.

Resources