How to find unused gems and cleanup gemfile - ruby-on-rails

I'm looking for simple, but good way to cleanup gemfile and make rails startup faster.
How can I get a list of all required gems vs all loaded gems.

bundle clean --force will remove old gems (or older versions of currently-used gems) previously installed, but not currently being used in your current Gemfile.lock manifest.

First, if you want to check what are the gems used by your project, I invite you to run gem server in your project folder root, then go to http://0.0.0.0:8808/
You will be able to understand the dependencies of all the gems your project is using. It will also show you all versions of the same gem.
To remove old versions of gems you can run as #changingrainbows mention
bundle clean --force
After this step run your gem server again and watch the result, a clean and understandable gem list with all dependencies.

It depends what you're after here.
If you're looking to remove old, unused gem versions, then bundle clean.
If you've been adding gems as you develop and have lost track of the ones you actually use, and have good test coverage, then try this answer.
If you want to reduce the number of gems rails pulls in at startup to the bare minimum, try gem_bench.

I think it is impossible. When your APP starts it loads gems from Gemfile.lock but it does not know if they (gems) are needed in your code or not. The APP inform you by raising an exception When something calls a class or method that is undefined if some needed gem is missed (if you remove it from Gemfile), but this can happen at any moment (not during starting your APP).
So if you are looking the way to clean up your gem list I think the best way to do it manually (I know it is not easy way). Analyse each gem to find out what functionality it provides and decide (or find in your code) if it is needed or not. Additionally tests (if you have them) should help you a lot.

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.

Should one bundle gems with the app?

Having just got a new machine I have taken the opportunity to try something new.
RVM is great and I have been using gemsets but after reading a few blog posts I have decided use switch to rbenv and use bundler to manage my gems exclusively as outlined in Ruby Rogues episode 45.
I do not collaborate all that much and if I do it is usually with one or two other people.
The bundler documentation details the ability to package up gems in to the vendor/cache directory by running:
$ bundle package
$ bundle install --local
Great private gems that can be checked in to source control; I guess making deployment to a clean server or collaborating easier?
However if you check your Gemfile and Gemfile.lock into source control then what is the need for bundle package?
Ryan Mcgeary advocates for this approach in this blog post form early 2011 and in another blog post from 2010 Yehuda Katz says that:
You might want to install your bundled gems to a different location, such as a directory in the application itself. This will ensure that each application has its own copies of the gems, and provides an extra level of isolation.
This isolation is quite like gemsets I suppose and I can imagine when you have a huge list of system gems it would be difficult to know which ones are actually being used by your applications.
So packaging gems with the application?
Is anyone doing this? Is this practice obsolete?
What's the best practice and what are the advantages / disadvantages of bundling gems within the app?
I think bundle package has a narrow set of usage cases.
Gemfile and Gemfile.lock deal with version locking, but in the end you still go out to rubygems.org and download the gem when you do bundle install.
The three scenarios I can see bundle package being useful:
1) I have a clean production environment, and I don't want to touch rubygems.org at all. This might be due to a security protocol, limited internet access, etc. In the end I have a entirely self-contained application package with all the gems lined up and ready to go, without really touching the server environment, or the internet.
2) I want to download the gem, unpack it, screw around with it, and use that particular one. Especially if I don't wanna deal with things like git, or forking, or any of that stuff.
3) From a development team point of view, you can say that all gems being used must be packaged and local to the app. You wouldn't have to worry about developers installing different versions, touching their environments, etc. This reason is kinda weak in my eyes, but I've seen this logic once or twice.
In the end, unless you have a use case where you're actively hunting for this ability, I'd stay away from it.

How can I reliably use code from github in vendor/gems?

I like to vendor as many gems as possible, except those that must be built on each platform (libxml, etc.) but sometimes I like to use some bleeding-edge code rather than the gems that are out there on the gem servers.
Can I clone a github gem directly into vendor/gems. I guess I could, but will it affect my app code since it is already a git repository? I would like to just do periodic git pulls for these couple of gems so that I don't have to update every gem and maybe break something.
Use of vendor/gems has been deprecated in favor of using Bundler and Gemfile instead. The vendor system had a number of flaws including a lack of support for compiled extensions, so it was never a complete solution.
You're better off locking your versions in the Gemfile as required. If you want to use bleeding edge versions, comment out the version declaration, remove Gemfile.lock and do a bundle install again.
It's often the case that the published version of the gem has a flaw you need to repair by forking and fixing, so it's easy to track this:
gem 'broken-gem', :git => 'git://github.com/myname/broken-gem.git'
The advantage here is that the Gemfile serves as documentation of what versions of the gems you require, and where to get them. vendor/gems leaves people in the dark as to where that version came from.

How do I freeze a specific gem into a Rails 3 application?

My question is very similar to How do I freeze gems into a Rails 3 application?, but I only want to freeze a single modified gem. The answers to that question seem to result in bundling all the application's gems.
In case it's relevant, I need to do this so the modified gem gets installed on Heroku.
I checked the bundle-install doc but it didn't seem to address this situation. I can't imagine it's that uncommon, though. Any guidance is appreciated.
Well, Bundler is going to freeze all of them, and the idea is that you want to freeze not only a single gem, but the collection of gems that produced a working copy of your app.
That being said, on your local dev machine, you can do bundle update [name of gem] and it will update just that one gem to the latest version within the restrictions specified in your Gemfile, which also updates your Gemfile.lock, which effectively updates just that one gem on Heroku when you next deploy.
If you're using bundler, which is the default for Rails 3, you can always fork the gem to your own git repository and add that definition to your Gemfile with whatever location it can be found at:
gem 'thegem', :git => 'git://github.com/cloned_to_me/thegem.git'
Another option is to use bundle package to save copies of the gems in vendor/cache. These can then be later installed using bundle install --local according to the documentation.
This is the closest thing to the Rails 2 "freeze" method, but has the added advantage of saving the gems before they are installed, not after, avoiding any platform-specific problems as was the case previously.
With thanks to those who answered the question with related approaches, I ended up going with the approach mentioned in this sister question. For the sake of clarity, this is what I did:
Repackage modified gem as its own gem. This takes a little finagling but is described well in the RubyGems Guides. Move said gem into your source directory (I used vendor/gems)
In the project's Gemfile, point to the location of the new gem:
gem "modified_gem", :path => "vendor/gems/modified_gem"
Add new gem to version control, make sure bundle install isn't messed up with funky settings (e.g. --local), and cross your fingers.
Someone also mentioned that it's possible to mix in changes to the gem instead of overriding source files. I don't know anything more about this technique except that it should be possible.

Resources