I don't completely understand the gemfile in a rails application - ruby-on-rails

What is the difference between installing a gem from the command line
sudo gem install gem-name
and writing your gem into the Gemfile and running bundle install?
I think the problem is that I don't understand the exact purpose of the Gemfile. So far it seems like it is a place to list all of the gems that your app is dependent on.

Installing a gem via:
sudo gem install gem-name
is going to install that gem system wide.
Whereas installing them via the Gemfile is specific for your rails app(to keep track of dependencies, version, app portability etc).

The best source of the whats and whys about Bundler, is probably this page:
http://gembundler.com/rationale.html
That page has great examples and explanation about why Bundler is useful and in some cases, necessary.

I always thought you write all gems that your app is dependent on in it, and then if you want to port your application somewhere else, you can run the bundle install and it'll grab the gems you need for you so you don't manually have to do it.
This might clear things up, I quote:
'It holds information about all the project dependencies so that you don't need to struggle to figure out what gems you need to install.'
http://blog.despo.me/42762318

Related

Gems in application build without bundler

I know that if application uses bundler, I can easily find all the gems installed by looking at the Gemfile.
Say, I am looking at the Rails 3 application that doesn't use bundler, how do I know what gems it uses?
Thanks
If it's not using Bundler, I don't know of a definitive way to identify every gem being used. You could search the entire app tree for require statements to start with, but that's not going to show most of them. Gems also require other gems internally, and will install their own dependencies, but those gems won't be referenced directly from your app's require statements.
If the app works and the tests pass (meaning you've at least got all the required gems installed), you could approach the problem by creating a Gemfile, listing the gems you know are needed, and then running your tests (or the app itself) via bundle exec, which will ensure that only the gems listed in the Gemfile are visible. Then you'll get failures related to missing gems, and can add them to the Gemfile until it all works. Once it's working via bundle exec, you'll know that you've captured all the requirements there.
If you're using RVM, you'll probably find it helpful to create a gemset for your app, along with a .rvmrc file in the app root, to take advantage of RVM's automatic gemset switching and Bundler integration. It'll make it easier to maintain the gem state going forward.
In any case, running gem list with the app in a working state will show you all the gems that it might be using, but without being scoped to a gemset or wrapped in bundle exec, you'll also see gems that were installed for other reasons that potentially have nothing to do with your app's dependencies.

What is the use of Gemfile in rails?

What is the use of Gemfile in rails?
How to use Gemfile?
During your development in Rails, there will be times where you will want to provide some functionality which is required by you, but either you don't know how to do or you don't want to implement it on your own since a lot of work has been put into its development by talented developers.
These developments which you might need (user authentication, message system, asset handlers, geolocation, pagination system, linking to exterior services such as Amazon AWS, and last but not least Rails itself) are called Ruby Gems. These are ruby software packages, not necessarily relating to Rails, but since Rails is based on Ruby, 98% of the gems can be made availble to your Rails webapp code.
Lots of gems can be found in github, but its funner to search for gems via ruby-gems or ruby-toolbox
Your gemfile is a list of all gems that you want to include in the project.
It is used with bundler (also a gem) to install, update, remove and otherwise manage your used gems.
The gemfile has another purpose - you can group gems in :development, :test, :assets, :production, etc groups and Rails will know when to include the gems. For example:
group :development, :test do
gem "rspec-rails"
gem "factory_girl_rails"
gem "guard-rspec"
end
Note that on Rails 4, the assets group has been deprecated
These gems belong to development environment and the test environment since they are for testing the application. You don't need them available in the production environment (you could, but that will bloat the memory unnecessarily).
So - To use the gemfile, simply write the gem you wish to install such as
gem 'devise'
make sure to install bundler beforehand (in your console/cmd/ssh) with
$ gem install bundler
and then write in the console
bundle install
you will notice another gemfile appears! Gemfile.lock
This file, as you will see if you open it with a text reader, lists all your gems with their version and their dependencies. This will come useful when you need to know which versions of the gems you installed.
For more reading on the Gemfile - read on the bundler page
for information regarding picking a gem you could start with this
Good luck and have fun!
Ok, so whats this Gemfile.lock that got created?
Gemfile.lock, as the name suggests is a locking on all the versions of all the gems that got installed. So if Gemfile is what required to be installed, the lock file is what got installed and what version are actually required to get the app up and running.
If you don't have the gems in that specific version (as specified in Gemfile.lock) rails will complain and you will have to either install the missing gems (via bundle install) or fix any conflicts manually (I believe bundler will give you some clues on that)
Some things to know about Gemfile.lock
if you accidently delete it, it will get regenerated when you run bundle install. If you accidently delete Gemfile, you are out of luck.. You should use git :)
Heroku doesn't care about Gemfile.lock since it will reinstall all gems. So for Heroku, you must set the gem version you want, or Heroku will always install the latest version of gem, which may cause issues
Keep the Gemfile.lock in your project so you will always know what version of gems make your app work properly.
Gemfiles are configuration for Bundler, which is used to manage your application's Ruby dependencies. That website includes a lot of documentation, including the Gemfile manual page.
Explanation by analogy
You want to build a car. From scratch. You need to build: a chasis, engine, corroborator, radiator etc.
Gems allow you to utilise car parts which other people have made before
Everyone's who's ever built a car has needed the same things.
You needn't reinvent the wheel. Why make your own engine etc when you can get it straight off the shelf? What if you could get one of the best engines around, created by the most talented engineers in the world, without lifting a finger? Are you gonna spend a year trying to make your own?
So basically rather than make everything yourself, you write down a shopping list of all the parts you need:
Rolls Royce Engine
AutoLive seatbelts
Michellin tyres.
PIAA Night headlights
etc etc.
That my friend, is basically your gem file!
Your system can have lots of gems ... thus can have multiple versions of same gem.
A Gemfile specifies the list of gems with their versions that shall be used/loaded/(install if not present) whenever you run your rails application. or anything with bundle exec . .
Firstly, what is a gem?
According to Wikipedia:
RubyGems is a package manager for the Ruby programming language that
provides a standard format for distributing Ruby programs and
libraries
Gemfile
A Gemfile is a file we create which is used for describing gem
dependencies for Ruby programs
Now, in very very simple words:
Gem can be thought of as a library which you can use in your code.
Example: faker gem
Your code can use the functionality of faker gem to produce fake data.
Now you can list all the gems that your project requires in the gemfile.
When you do a bundle install, all the gems in your gemfile are installed for you.

When to Add to Gemfile and when to just install via CLI

I'm just getting started with rails and I'm a little confused reading through different documentation as to when you should add the gem to your gemfile and when you should just "gem install XXX"
For example, when installing rspec and guard-rspec. I see that some folks will:
gem install rb-fsevent
and some people put it in their gemfile and bundle.
Which is the right way and how do you know which to choose? Thanks!
The Gemfile records and manages all the dependencies for the application. When you list gems in the Gemfile, bundler sorts out any version conflicts and makes sure that the correct version of the gems are used with your application.
When you set up the application in a new environment (such as when your colleagues pull your changes from version control or when you deploy to a production web server), Bundler can use the gem file to ensure that the environment is set-up exactly as you had it in development.
So, anything on which your application depends (any code you call from your application for example), needs to be in the Gemfile. This includes libraries that you use for testing (although they can be excluded from the production environment).
Gems that are not dependancies of your application don't need to go in the Gemfile. An example would be guard which is more of a development tool than an application dependancy. You can install those with the gem command.
Typically though, most things you're going to want to install probably need to be in the Gemfile.
It doesn't matter if you install it with the gem command however. You can still put it in your Gemfile afterwards and Bundler will work out what to do.
All gems you will use in your application you should put into Gemfile.
All gems that will be just serving your application you'd better keep out of Gemfile.
For example. You need paperclip and mysql2 gems to store pictures and data, so put them into Gemfile. And you need magic_encoding gem to do some helpful stuff. But as far you are creating it straight from console, you don't need it in your application. Keep it separate from your app.
You use test frameworks when writing code, so put them into your Gemfile.
You use passenger gem to deploy your apps, but you never need to use it right in your code - don't put it into Gemfile.

Can you disable Bundler in rails 3?

It causes so many deployment issues it's ridiculous. Most of the time I don't care what version of gems are used, just want to use the latest one.
UPDATE in response to comments:
Here are a couple of examples off the top of my head:
developer A is using a pre-release of a gem so when he runs 'bundle update', the Gemfile.lock is messed up for everyone else and if you deploy it, there goes your site.
A bug in a gem gets fixed so we run gem update across our servers, restart rails and yay, bug fixed! Oh, but wait, it's not fixed? Thanks bundler. What should have been an easy fix is now a full code deploy across our servers.
That's just a couple off the top of my head. At least let us decide if we want to lock in gem versions or perhaps at least allow a range of versions for instance any 2.X version.
UPDATE 2: And yet another issue when there are windows developers on the team
Here is what's showing up in a windows Gemfile.lock:
nokogiri (1.4.4)
nokogiri (1.4.4-x86-mingw32)
Wow, this is just awesome. Sure makes for easy teamwork and deployment.
I recommend starting to use two techniques with your development and deployment:
Specify version number of gems in your gemfile.
For example:
gem "rails", "3.0.1"
gem "will_paginate", "~> 3.0.pre2"
This way, when you decide you want to update rails, or will_paginate, change the version numbers in your gemfile.
Only update certain gems
Rather than the generic bundler update command, run
bundler update rails
This will only update the rails gem to the newest version, rather than get the latest of all gems.
If you use both 1 & 2, you'll have a happier experience.
Then, simply, don't check your Gemfile.lock into source control. All of the specific problems you listed are solved.
Of course, you are sacrificing the enormous advantage that Bundler gives you over any other dependencies management system.

How do I freeze gems into a Rails 3 application?

I want to freeze a specific gem into my Rails application.
In rails 2 there was this command:
rake gems:unpack
I can't find that command in Rails 3.
So, the short answer is, you don't.
When you modify your Gemfile, and then run bundle install or bundle update, bundler handles the dependency resolution for you and determines the best (newest) versions of each gem you've required that satisfies the entire dependency chain (you won't get a new version that breaks another gem in the dependency list, etc.). You can also of course place a specific version, or a '>= 1.2.3' specification or whathaveyou in the Gemfile using the familiar syntax from the config.gem days, and bundler will make sure to satisfy that as well (or won't produce a Gemfile.lock if there is no valid resolution).
When Bundler does its business, it creates the Gemfile.lock file, which (and this is provided you use bundler alone for managing your gem on all workstations/environments/deployments) performs the same function as freezing all of the gems you've required. For free! (Check this file into version control!) If your new development intern pulls down your source on a fresh machine, it takes one bundle install and the exact same versions of the gems that you have installed are on her machine. Push to deployment, and do a bundle install --deployment there (or more likely, throw it in your Capfile), and the same gems are installed (this time into vendor/bundle, configurable). Bundler is used in Rails 3 to manage loading all of the gems, so wherever you've told bundler to install them (whatever your normal gem install location is by default, or BUNDLE_PATH (which is recorded in .bundle/config if you install with bundle install --path=foo otherwise), bundler will load the right ones, even when they differ from system gems.
You don't need to unpack the gems and check them in to your app, because it doesn't matter: you're guaranteeing the same versions are being called regardless of where they are installed, which will likely vary from machine to machine anyways (.bundle/ should not be checked in to the repo) - so why stick another 60-80 MB of files into your repo that you won't ever be changing or using? (incidentally, this is why I wouldn't recommend a bundle install --path=vendor/gems like nfm suggested - it's not necessarily wrong, there's just no benefit to it over the normal bundler workflow, and now your repo size just ballooned up).
DO NOT USE THE "RECOMMENDED" ANSWER BY NFM!
Instead, review the Bundler site, particularly the page on deployments:
http://gembundler.com/deploying.html
The short summary is to use specific versions in your Gemfile and run bundle install --deployment on each target system where you need the exact gem versions.
Using the --path option will install the gems, but it's not really what you want to do. As Matt Enright said, you just bloat your SCM with stuff that bundler can handle smartly on each target environment.
I haven't had to do this yet, but I believe it's all handled by bundler.
When you create a new rails3 app, the rails dependencies are put into your Gemfile. You can run bundle install to install them. By default, they are installed into your BUNDLE_PATH.
If you want to install them within your app, you can specify where: bundle install vendor/gems.
I had to do this for typus gem deployment on Heroku as you can't run a heroku rails generate typus on Heroku given it's a read only file system. I didn't want ALL gems put into my app, just the one that was causing me grief. Here are the steps that lead to success:
create directory in app_name/vendor/gems/gem_name (optional) ... in my case /app_name/vendor/gems/typus
add the following to gemfile (this tells bundle where to find and put the gem source):
gem 'typus', :git => 'https://github.com/fesplugas/typus.git', :path => "vendor/gems/typus"
then from within your app directory (this installs the gem into your app):
'gem unpack typus --target vendor/gems/typus'
then bundle install
then .. in my case... commit and push to repository and then deploy up to heroku... you may have to run a heroku rake db:migrate
Assuming you already have bundler gem installed:
$ bundle lock
$ git add Gemfile.lock
You can bundle install on dreamhost without any issues. If you are on shared the environment is already setup to store them locally in your home directory. If you are on a VPS or Dedicated you can run bundle install as root or just add this to your .bash_profile
export GEM_HOME=$HOME/.gems
export GEM_PATH=$GEM_HOME:/usr/lib/ruby/gems/1.8
I think what you are looking for is
bundle package
checkout the man pages here:
http://gembundler.com/man/bundle-package.1.html
I second the answer by tsega (updated by coreyward). "bundle package" is the generic answer.
The poster didn't ask WHETHER to freeze his gems. He wanted to know HOW. Answers like "Just don't do it" aren't helpful at all. Yes, it turned out his specific problem was a little different than that, but while "bundle package" might have been overkill it still solves the problem.
I have worked on a lot of systems, and on some you just don't have full access. Installing gems on some systems just isn't an option. So unless you package them, in general you're screwed. There are different workarounds for different hosts and systems, but none for some.
Pod - If you need to modify the gem, the best practice to do this would be forking the project, making the change, then using the 'git' flag in bundler:
git 'some_gem', :git => 'git://github.com/me/my_forked_some_gem.git'
This way you'll be notified when the gem is updated.
The command that you want is bundle package which just unpacks the gems and dependencies at vendor/cache folder.
But just a notice, the :git => .... kind of gems wont get packaged. You have to hack a way out for :git => ... related gems to get packed.
Cleaner instructions for the gem unpack and :path => option:
https://stackoverflow.com/a/8913286/555187
A lot of comments are somewhat saying that it's not useful to use the bundle install --path vendor/gems, but those people who are using Dreamhost, it should note that you cannot use bundle install in Dreamhost.
The solution is to get all the gems into the vendor folder and upload the whole thing to the Dreamhost directory.
There are other solutions to turn around this, but it's much more complicated to do.
Well I have to modify slightly one of the gems I need. So I need to keep it inside my Repo. So what NFM mentioned is what I probably need.

Resources