Specify gem version or always use the latest one? - ruby-on-rails

I code a RoR webapp on my sparetime. Like anybody (I guess), I use gems (about 20).
A few times, I had errors when deploying the app in production environment because I wasn't specifying the exact version for all my gems, so some of them were updated which led to bugs.
I'm worried about staying in a particular version for all my gems and when I need to update one (or some) of them, the whole thing break down (I had problems making gems for flying-sphinx and twitter to work together after an update).
My question is : should a part-time coder fix once-for-all the version of the gems used or is it worth the time to check each update ? How do you manage your Gemfile ?
Also I think that when you're full-time, you should always keep to date (security, performance) but is it really true ?

I mostly stick with this kind of version specification:
gem "blah", "~> 1.4.2"
which means a version number >= 1.4.2 but < 1.5.0
Most gems follow a semantic versioning scheme or at least only break stuff when doing a version jump. This way, I am 'safe', but still get the good parts (bug fixes etc.).
Locking down the exact version numbers is the idea behind Gemfile.lock, so I check this into version control, too. This approach has worked perfectly for me so far and I have never had problems with this approach.

Related

versioning best practices for ruby gems

I'm adding new gems and functionality to it often. Before my last release some of my code broke in my dev environment and I found out it was because some of my gems (CarrierWave and jQuery in particular) had been updated and didn't work with some code.
What's the best way to manage gems regarding versioning? Some seem to say that you should always specify the version number in your Gemfile...but for all gems? Just some?
I know that for some gems you may have to store the version numbers because of bugs, etc. But these aside, in development there are times where I'm adding new gems and may need to do a bundle update to get the new stuff working but then don't want to break old stuff.
I have good tests to hopefully catch a lot of errors before pushing to production. How are other users ensuring gem update may not break completely unrelated functionality when in development?
Unfortunately, if you dont' want you app to break because of backward-incompatible gem updates, you do have to specify gem versions. What I found to be a good practice is using the pessimistic operator ~> to specify gem versions. For example:
gem carrierwave, '~>0.6.0'
This means the carrierwave gem will be frozen at version 0.6, but bundle will install any minor, backward-compatible updates and bug fixes, which are usually increments of the last number (0.6.1, 0.6.2...). That means you can update your bundle without running the risk of breaking something (no more flinching when running bundle update).
You can also use the pessimistic operator on major versions:
gem devise, '~>2.0'
Meaning bundle will update to versions 2.1.0, 2.2.0, 2.2.1, 2.3.0, but never to 3.x.
Some considerations:
You don't have to specify all gem versions, but it's good practice. I don't specify versions of my own gems, for example. But every third party gem has its version specified. Otherwise, I'd be trusting my code to things beyond my control.
You still need to have a certain amount of trust in the gem maintainers to use the pessimistic operator. A reckless maintainer still could release backwards-incompatible changes in a minor version. In those cases, I lock the minor version (no pessimistic operator).
If you specify gem versions, you'll be making bundle's work of resolving gem dependencies a lot easier, meaning it'll do it much faster.

Upgrading Rails Versions

I know that to update Rails, you update the version number in your Gemfile and then bundle update but what I am getting confused about is how do you know if anything else has changed?
How do I know if there are config options to add or anything else anywhere. Contents of files or whole directories.
Any clues?
Rails upgrades fall into the following categories;
Patch version upgrades (e.g., 3.2.10 to 3.2.11)
Minor version upgrades (e.g., 3.1.X to 3.2.X)
Major version upgrades (e.g., 3.X.X to 4.X.X)
Major/Minor Upgrades
Major and minor version upgrades require a lot of work, and I'd urge you to look out for screencasts from people like Peepcode or Peter Cook.
Sometimes its easier to do a rails new and copy all the initializers and config files over the top of your app, and do a diff to find what's changed.
I'd always suggest doing a minor version at a time.
For example, if you are still on 2.3.x, you should first upgrade to 3.0.x, then the 3.1.x, then to 3.2.x
Patch Upgrades
Patch version upgrades are generally simpler (and important since they often include security fixes). Look out for any deprecation notices in your logs, and fix the changes.
Do a Gemfile update, run your tests, and most of the time it'll be fine.
It certainly depends on which versions you're upgrading between. In general, Rails does a pretty good job documenting what you'd need to change in the release notes, for example: http://edgeguides.rubyonrails.org/3_2_release_notes.html
Sometimes, deprecation notices will help you after you upgrade. Alternatively, you can rails new a brand new app, and compare configuration files of the clean-slate app with your existing one.
The Railsdiff.org site can provide the difference between the contents of a vanilla Rails project (ie as if running Rails New) between any two versions of Rails going back to 3.0.0. I find this particularly useful to determine if there have been any changes to the standard configuration options between versions or if there are new files added/removed from a standard project which you may want to copy over to your existing project.
This won't provide any insight into what has changed in the framework itself, for that you'll need to jump into the change logs for each release. Easiest way to pick them up is check out the Ruby on Rails blog which includes notes and links for each released version.

Can I edit the gem installed using 'gem install' or from my gemfile?

On my server (or laptop for that matter) whenever I install a gem using:
gem install mygemname
or in my gemfile:
gem 'mygemname'
It will install on the computer to some folder on my computer.
Can I go to that folder and edit the file if I want to say add some logging etc.?
If this is not possible, I remember reading that you can have the gem source code installed in your rails 3 application under the 'vendor' folder. How do I install it locally so I can edit it and add logging to it (to learn how it works etc.)
Can you?
Yes
Should you?
Absolutely Not.
Why?
Modifying the gem source makes it very difficult to upgrade to newer versions of the gem
It's much harder to debug an issue
It will cause HUGE headaches down the line
It makes it difficult to work in a collaborative environment (does every developer have the correct hacked gem?)
It causes questions like these (i.e. where should I hack a gem?)
Solutions
There are a few ways to solve this problem:
Submit a Patch
If you feel that this 'change' would benefit the entire community, find the source code (most likely on github), fork, apply the patch, write tests, and submit a pull-request. If the developer agrees that your patch is viable, it will be merged into the project and released with the next version of the gem.
Advantages
You are helping the community
You have a local copy of the gem (since you forked it) on your development machine
Disadvantages
You have to wait for the developer to accept your patch
This can be pretty time-consuming
Re-Gem
If you don't think this is something the entire community would benefit from, but you still want to allow your other developers to use the gem in a systematic way, fork the existing gem, apply your patch, rename the gem, and publish. in this case, it's good practice to prefix your custom gem with the original gem name. For example, if the gem was named foo, you would name your gem foo-my-company. You now can choose to open-source that gem (push to rubygems) or push it to a private development gem server within your organization. You still must source the original gem author in your re-gem!
Advantages
Don't have to wait for a developer
Central code base
Easily shared
Disadvantages
Difficult to update from original gem
Can be cumbersome to maintain
Local Lib (monkey-patch)
You can create a monkey-patch inside your application and override any methods or properties that don't fit your current environment.
Advantages
Quick and Easy
Easily Shared (via git - just include the patch file in your repo)
Disadvantages
Updating the gem is difficult
It's not clear to other developers that you are modifying the Gem's core
Harder to debug (is it an error with the gem or your patch?)
Fork and Source
This is my recommended option. Why did I put it last - the other ones are more common. In this method, you fork the gem from its original repository (probably on github), and then source your gem from your git repo. For example, say the gem was named foo, you would fork foo to username/foo on github. Apply you patches, changes, whatevers. Then in your Gemfile:
gem 'gem_name', :git => 'git://github.com/username/foo'
This will install and compile the gem from source at your repo every time the bundle command is run. You can also specify a particular tag and branch (recommended to stability).
Advantages
You can easily update upstream (you have a fork - pull from the upstream, merge, you have all changes)
Version control is easy (use tags and branches for various versions)
Everyone has access to the same gem source
Easy to manage updates
Disadvantages
Your "custom" code is public (although you could use a custom git server instead of github to solve this)
Conclusion
Each method has its own advantages and disadvantages (which I've tried to enumerate as best as possible). In any event, the method you suggested is not an advised method for solving that problem.
If readers have comments about other advantages/disadvantages, please list them, and I'll add them to my answer.
Sure, it's just code.
Should you? Not in general, since it could be re-installed, updated, etc.
Since you can re-open classes IMO it's safer to monkey-patch, embrace and extend, etc. This isn't always as practical as direct modification, of course.
For educational purposes (when it doesn't matter if modifications are lost), it's fine, and makes more sense than duplicating everything. AOP-ish logging is often doable w/o modifying the original source, though. Sometimes cloning a repo and using it, particularly during exploratory phases, is cleaner.
Dave Newton's advice is wisdom and you should take it, but there's nothing wrong with taking a look at it to learn something. Running gem env will show you where your gems are installed; the lib directory is where you tend to find the meat of the code.
We have had this discussion at work, and it is a practice I discourage.
Gems are made to be updated when improvements and bug-fixes are made. That will instantly wipe out the changes you have done, breaking your code.
You can freeze your version by making it read-only, or use bundler or copying the entire Ruby distribution, but in each of those you are going against the flow.
Instead, I recommend:
Write a patch to the method in question in one of your own files. I've copied the method definition into a separate file in my app's lib directory, and made the change there, then required it last, allowing the method to be fixed without subverting Gem's normal use.
Submit your change to the gem maintainer as a patch, along with your reason for needing the change.
Remove the file and the require if/when the change is accepted.
I used to work at a major corporation that decided it was a good idea to make a patch to one of the source files in their mail system. The software was not something they wrote themselves, so, as time went by, they spent more and more time having to roll in their "special" changes to the software as the vendor grew the product. Eventually, it took months to roll in the changes and made the software fragile, which is not a good thing for something that is a core-business service. Ruby's ability to redefine a method would have saved them untold dollars and months of work.

Is it okay to use Rails 3.1 for a new project? Is hard to convert over?

I have just started using 3.0.7. I am about 2 weeks of development in.
I was wondering if I should keep building for 3.0.7 or switch to 3.1 before I have too much code to port over? I like most of the new features (my only fear is not having good error messages when I use coffeescript), so I'd like to code towards the latest and greatest if it's relatively safe.
The javascript standards look interesting, and the attr_accessible fix sounds like it's very much appreciated.
Is Rails 3.1 compatible with all the gems out there though?
Also, if I go the 3.1 route, is hard or easy to migrate my project towards it? How might one go about that?
I guess this is a lot of mini yet related questions. I'd really appreciate some answers. Thank you.
I think if you want to ride on Rails 3.1 you should do it :). As for me I have some projects on Rails 2.3.5, 3.0.5 and would like to port them on Rails 3.1 but there is to much code there :). So don't be afraid and go to the fresh stuff (unless your code overflow :) ).
Rails 3.1 are pretty stable for now (I didn't have much problems with installing and using it)
If you're only two weeks into a project then it makes sense to stay on the edge and move to 3.1.
The way I'd do it is clone my project to a new dir (you're using git / similar version control, right?), change the Rails version in my Gemspec, run tests and play around to see what got broken (if anything). Based on the results you can figure out whether the effort is too great.
Regarding gem compatibility, hardly anything is compatible with all gems out there. Since you're two weeks in, you probably know which gems you use. Test like I suggested and you'll have an idea whether it's compatible with what you need. If you're using popular gems, then they'll most likely be updated to work with 3.1 soon enough.

How to get a rails commit into my gemmed version

Rails 2.3 was released last week and I installed it with gem install rails. Everything is working fine. However, I noticed a bug, so I searched a bit and sure enough a new commit was accepted 2 days ago that fixes the same bug I saw.
How can I get these latest changes into my version of rails that I'm running locally?
I tried gem update rails --include-dependencies but it doesn't update rails (as I assume because I already have the latest gem 2.3.2). So, how can I get the last few commits into my version of rails?
Thanks.
I've never used Edge Rails but I imagine that's what you'd need to do. Edge is the last commit and may have other bugs in it.
If the changes are small, just edit the code. Once you've done that you may be able to freeze the gems after you've edited them, but I'm not sure that freeze will freeze the rails code itself. If it does then everything should still work fine, otherwise you'd also need to edit it on your production gems too.
Hope this helps, doubtless some Rails Edge god will come along and tell us the easy way.
If you use git to checkout the release, then you can use git cherry-pick to grab the specific patches that you want for your own personal tree. google for git cherry-pick for more info (and if you aren't familiar with git, it's worth learning!)
I found some comprehensive instructions for this here:
http://www.napcsweb.com/blog/2008/04/24/create-a-new-edge-rails-project
If you freeze rails to the 2.3.2 version, you can then edit the file yourself and be sure that your application will use that edited version of rails.

Resources