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.
Related
I'm used to defining gemfiles with simple commands, like gem 'devise'. I'm now putting my App in production through a dockerized container on AWS, together with a pipeline that pulls and builds new containers based on pushes to my master branch on Git. This means that every time I push a new version, AWS will rebuild the entire app from scratch, also installing all the latest versions of the gems.
I'm having some concerns what will happen when there are new versions of gems. This could of course mean that my code could stop working, if the included gems change their behaviour or methods.
What is the best practice is this case? Should I start explicitly defining what versions of the Gems I want? And if so, how do I make sure that I do profit from the fixes that are provided?
I'm considering defining all my gems like this:
gem 'devise', '~> 4.6.0'
# Or
gem 'devise', '~> 4.6'
What would be the most flexible, but "ensuring" I don't run into any issues in the long run?
Unexpected version changes should usually be prevented by Gemfile.lock, that contains exact versions that were last installed/upgraded and is committed alongside gemfile and can be used to ensure production can be built each time exactly the same. First I'd look into why your build pipeline does not use it.
Even if you have CI and good tests coverage that will prevent production from breaking, it's much better to be sure that something broke not because of your changes, but a gem update. Thus gem updates, even to minor and patch versions, should come in separate commits.
As for versions in gemfile itself - you should specify version dependencies according to version policy of that specific gem (even when relying on a lock-file). Most gems use semantic versioning, so that gem should not break anything within one major version (~>4.6 option) and updates should not require major changes to your app (but anyway there may be deprecations that flood your log or some regressions, so in any case it's better to have a version tested before production).
To stay updated about new versions of dependencies - periodically run bundle outdated to see which gems updates are there.
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.
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.
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.
I want to know should I specify gem version for each gem I add to Gemfile or not. Earlier with few of my projects I didn't specified any versions for all the gems and bundler took care of it, which worked quite well as well.
But recently I got to work on few project which were under development for last 6 month. In that project, many of gem versions were specified in Gemfile only and Gemfile.lock was ignored. That caused a lot headache to finally resolve version conflicts and upgrade few gems.
Also got to know that it's bad practice to remove Gemfile.lock from application version control - nice article by yehuda - http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
So, my question is should I specify version for each and every gem I specifiy in Gemfile or just specify name and bundler will take care of version ? What is best practice to handle this ?
UPDATE -
Updating this question to correctly specify the problem, as a Gemfile sovles many problems :)
Prob 1 - Every developer should have same version of gems.
Actually adding Gemfile.lock into version control solved this problem. Developers just have to take care that they run 'bundle install'/'bundle' rather than 'bundle update' as this will update versions as well.
Prob 2 - Some gems version, if changed, brakes application code.
Actually with omniauth,there are this type of issues, as API are changed from one version to another. And yes, to keep application working, versions will need to be specified for this gems.
My Prob. -
So, in my gemfile, as versions for both A and B are strictly specified, and as they both depend on different versions of Z, which is there dependency, I even can't run the bundle install or bundle update. The only solution was to remove versions and let bundler to take the call. That's why I had question like -
Gemfile.version_specification_mandatory? #=> true/false
I think it's best to not specify gem versions in the Gemfile. On rare occasions, it may be necessary to specify a version--e.g., when a newer version breaks your app. But specifying versions for all of your gems is usually overkill. The Gemfile.lock file (which you don't edit, but you do check into version control) will keep newer releases of gems from being used in your app, until you explicitly upgrade to them.
If you are using the gem for something that is available only in a specific version, you need to specify the version.
Bundler installs the latest version or uses the available version on the system if no version is specified. This works for the developer because the latest version has the feature she needs. But if the feature gets lost in the future versions of the same gem and the version is not specified in the Gemfile, all subsequent installations of the gem for different people or different machines will produce undesired effects.
I have faced these problems particularly for will paginate 3's release candidate versions.
I don't recall how Bundler worked back in 2011, but in 2021, if you don't specify a version in your Gemfile, you can't assume that Bundler will always automatically install the latest version. Instead, Bundler will try to find the right combination of versions to make all your gems compatible with one another. This could lead to some gems being downgraded, which is probably not what you want or expect. Bundler will do this silently, without a warning message, which you could argue is a broken user experience.
On the other hand, when you specify a version, if there is a conflict, Bundler will let you know and you can then decide how you want to proceed.
I recorded a screencast recently to show a real example of an older version of a gem being installed when the Gemfile didn't specify a version number.