Modify Gem, then ensure it gets reloaded? - ruby-on-rails

I've got a gem that I'm modified a bit of code in, but when I bundle install or update, the changes to the gem aren't reflected in my app. Is there a way to ensure the changes are captured and reloaded in my app? Thanks.

You should never update code directly in the gem. Instead, choose from one of these options (from preferred to less preferred):
Send a pull request to the gem maintainer
Monkey patch the gem in your app
Fork the original gem and maintain your copy.
If you need help with any of this, that's a topic for another discussion, but please, don't edit code in the gem itself.

Make sure you modify the installed gem by using bundle open . Make the changes, save, then if your app is local and running in standard development mode (no caching) the changes will be immediate and worse case you can restart your app and they will be picked up. If not, you aren't making the change to the gem your app is using. A change like this will survive a bundle install, because bundler will have no reason to update your gem. However, if you run bundle update and a new version of the modified gem is installed it will get rid of your change. A good approach is to fork the original gem on github, make your change and have your app point to your forked copy on github.. then even when you deploy the app it will find and install your modified code. Also if the change is something useful for everyone, make a pull request to the original project.

Related

How to add specific, not released yet commit to Rails current release?

I would like to add this change https://github.com/rails/rails/commit/94584c2510743a45d9030d1b94dd33a074518b17 to release/version 6.0.3.3. How I can do this? Is it smart idea to do so? It sounds for me like I would like to cherry pick this change?
Do as follows:
Create rails fork of the unreleased version that you need
In your Gemfile, add gem 'rails', git: 'https://github.com/you/your-rails-fork'
Run bundle
When it is released, restore gem 'rails' in your Gemfile
It is not a bad idea to do so, as long as:
It actually gets released at some point and you get back to the community-kept official version when it does (for the security reasons mostly).
You don't introduce any custom changes in the forked repository - if you do, you might get in trouble when trying to get back to official rails.

Working on gem within a Rails app

What's the easiest way to work on a plain-ole Ruby gem, and then quickly turn around and run it in a Rails app?
I like to keep application logic out of Rails. Encourages code reuse across projects, and keeps my Rails app clean. It produces, however, an ugly workflow:
Test my gem. rake test
Build my gem. gem build ...
Upload gem to private repository (currently using Gemfury). fury push ...
Update my gem from within Rails (bundle update ...)
Run my Rails code.
Yuck. I'd like to simply save my file in the library, and then watch it work in the Rails project.
Clojure's Leiningen has a concept called "checkouts", allowing you to work on several libraries within one.
Techniques, anyone?
Use Bundler's path directive.
gem 'my_gem', :path => "~/my_gem"
You'll still have to restart the Rails server every time your code changes to reload it, but you won't have to go through the whole build-and-publish step for each revision. Be sure to update your gem reference to something production-worthy before pushing your code.

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.

what is the best way to change a gem locally and then revert changes

I want to write some puts statements to gem files, but I am afraid that I may forget to revert my changes. But I still want the ability to change gems locally and then restore their original versions. I am using bundler and gemsets for different rails projects. One way to do so is to store which gem i changed, uninstall it and then reinstall it. Other way is to create a temporary gemset, import all gems needed, make changes to it, and then destory the temporary gemset. what are other ways to change gems locally and fast, and to get the original gem once done with debugging?
use a version control system like git or subversion. It allows you to make a savepoint on your files, make some changes, and rollback to an earlier version if something goes wrong. There are many other features, but it would be too long to describe here.

How do (or can I) hack a gem temporarily while looking for a bug?

I have a gem installed in my home directory on a laptop (eg not THE server). I have installed ruby 1.9.1 and also some other gems, notably right_aws - which allows access to s3, etc with ruby.
All works, except there is a bug when I do a query on SimpleDB, and the returned list of items includes an item with any two byte utf-8 character in its itemName().
So I look through the sources of the right_aws gem installed on my machine, and I can see some places where I would like to test a fix. If I edit the file, save changes, (needing a password), then restart the server (script/server), it ignores my changes.
I am quite new at ruby - do you have to 'compile' or other similar move to get the source code changes made take effect?
I can see the edited file is changed by viewing it in terminal, etc.
Are you sure you're editing the version that you're application is picking up? If you're using Bundler it'll download it into a seperate folder (hidden in your home directory). If not check using gem which right_aws. Make sure the file you're editing is the same as the one reported by that.
Install it as a plugin. Then you can change the source in vendor/plugins and go back to the gem version later when it's fixed.

Resources