Creating a gem server, which I can release gems to - ruby-on-rails

I've written a few gems that I've released to rubygems using Gemcutter and the source stored on github.
I have issue that I need to create a gem that can't be open source and also not available to the community, but only to members of my team.
I am aware that I can store gems locally and target them in my Gemfile, however I'd like to be able to do
rake version:bump
rake release
or similar. That would bump the version and push it to my gem server and still keep older gems so that people can install older versions of it.
Seems like it should be fairly simple to do. I'm just missing how to do it

This is fairly simple if you have a server you can host your private gems on. Setup a subdomain, something like gems.companyname.com and setup a virtual host to host your domain. You'd point that virtual host to a folder like you would any website and setup the gem server from there.
Example:
mkdir /var/www/gemserver
mkdir /var/www/gemserver/gems
cp private-gem-0.1.0.gem /var/www/gemserver/gems
cd /var/www/gemserver
gem generate_index
/var/www/gemserver would be the root directory. Lastly all you'd need to do is add a new source to your Gemfile
source 'http://rubygems.org'
source 'http://gems.companyname.com'
So anyone that knows about your custom domain can get access to the gems. The only pain is every time you rebuild your gem you need to run the generate_index command again after you upload your gem to the gems folder.

Related

Where are Ruby gems located on a server?

My understanding is that the gemfile in a Rails app only provides references to the actual code of these gems on your local computer. So when you're running your app locally, it's pulling the gem code from your local computer. What happens when you deploy though? The server runs your rails code, but does it also hold all the references in your gem file and automatically download them as well?
Yep. If you deploy on Heroku, you can see bundler doing its work and pulling down the gems.
As per the Bundler docs, you can use bundle show --paths to see exactly where your gems are being loaded from.
Additionally, if you aren't using bundler, you can use the command gem environment to see gem paths on the system.
See this existing answer for more info: How can I find where gem files are installed?

Bundler unable to find custom gem

I have a custom gem built as a .gem file that I am trying to reference from my Gemfile. I have placed the .gem file, along with the .gemspec, in the vendor/gems folder. My Gemfile has the following line:
gem 'umlgrader', '1.0.0', :path=>'vendor/gems'
When I run bundle install, it claims to have found the gem but it says it is "using" the gem, rather than "installing" it, even though the gem was not previously installed on my machine. When I try to run my app, I then get a NoMethodError when it tries to call any of the methods in the gem. Why isn't Bundler installing the gem?
I have gotten it to work by unpacking the gem in that directory and then editing the Gemfile as follows:
gem 'umlgrader', '1.0.0', :path=>'vendor/gems/umlgrader-1.0.0'
This solution is less than desirable. I would prefer to be able to install the gem using Bundler since I am trying to deploy the app to Heroku. I have already tried a lot of the solutions I have found online, but I am open to any suggestions.
EDIT:
Some of the other pages I have already gone through and tried:
Bundler: installing a specific .gem file
How to use Bundler with offline .gem file?
How do I specify local .gem files in my Gemfile?
I also noticed a lot of people suggest pointing to a Git repository containing the gem. I would rather not do this if I don't have to.
The Bundler documentation is somewhat cryptic on that topic, but that is the intended behaviour of Bundler. In order to use the path option you must unpack the gem at the desired location.
But that should be no problem for Heroku. After all, you are still using Bundler, even if the gem is already unpacked. It's just a step less in the gem installing process...
Without Docker
You need to clone the repository from github (or other source) to your custom folder. In example below the steps to reproduce how I use custom path to edit gems in a separeted folder:
In this case I use a custom_gems folder inside /bundle: mkdir /bundle/custom_gems.
cd /bundle/custom_gems.
git clone <gem-repository-source>. Is necessary to clone because if you copy from other folder in your computer probably some files are missed.
Set in your Gemfile: gem '<gem-name>', path: '/bundle/custom_gems/<gem-name>'.
Restart you application.
In docker-compose (or Docker)
With docker is little different, in this case I use a /gems folder inside my rails application folder: mkdir <my-app>/gems.
cd <my-app>/gems.
git clone <gem-repository-source>. Is necessary to clone because if you copy from other folder in your computer probably some files are missed.
Set in your Gemfile: gem '<gem-name>', path: '/bundle/custom_gems/<gem-name>'.
If you use docker-compose, you need to bind folders with volumes config, like below:
volumes:
- ./app/gems:/bundle/custom_gems
With this, your local folder (your machine) copy files inside ./app/gems to /bundle/custom_gems in Docker container.
Restart service.
If you NOT use docker-compose, you need add in Dockerfile some like:
ADD ./app/gems /bundle/custom_gems

Ruby on Rails - production installation without internet

I need to get Ruby on Rails (3.0.9) installed onto a production server that doesn't have internet access. Ruby itself is already installed, and is the same version as on my development machine. But there are no gems installed at the moment.
Running gem list -d on my development machine, I can see a pile of gems installed at /usr/lib/ruby/gems/1.8/gems
Basically, I am wondering whether it is possible so simply tar up the gems directory on the development machine, copy to production, and unpack it into the corresponding directory. I would simply try it and see if it works, but I'm aware this is a production install, and I'd rather not be left with something that looks like it works, but doesn't quite.
Is there a better option? e.g. copy these files to somewhere else that I set up as a gem repository?
Bundler offers this feature with bundle package.
Note that this doesn't include gems with sources included via :git or :path options.

Using Hunspell With Heroku

I'm building a Rails app that uses Hunspell and the hunspell-ffi gem so that Ruby can interface with it. I'm deploying the app to heroku, but unfortunately it needs Hunspell to be installed on the server in order for the gem to work.
Is there any way for me to install Hunspell on Heroku? Or am I going to have to migrate to EC2?
Thanks in advance :)
You need to build the required Hunspell library and include it in your Heroku project directly.
Heroku runs on 64-bit Ubuntu therefore the binary has to be compiled under that system. The best approach is to simply use Heroku's Vulcan build server to compile on a Heroku instance.
Compiling for Heroku
gem install vulcan
vulcan create vulcan-compile-me last argument is your own app name.
Download Hunspell source
Extract
vulcan build -v -s ./hunspell-1.3.2 Tells Vulcan to build it and downloads the finished product automatically to /tmp/hunspell..
The build server requires the cloudant add-on, this is installed automatically but you have to make sure to have a verified (credit card added) Heroku account. If you get errors in step six of no build output then do heroku addons:add cloudant --app vulcan-compile-me
Adding to Your Project
Extract the Heroku Vulcan build tar from /tmp
Copy the entire lib folder to vendor/hunspell in your project root directory
Tell Heroku where to look for libraries: heroku config:add LD_LIBRARY_PATH=vendor/hunspell/lib.
Install Dictionaries
Download some dictionaries from Open Office and add them to your project. A good location is a folder called dictionaries at root level. This path is then referenced when initializing Hunspell in Ruby.
http://extensions.services.openoffice.org/dictionary
ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/OpenOffice/contrib/
Using
Install your favorite Hunspell gem, I use hunspell-ffi. There is a newer gem for Hunspell but I prefer the previous FFI gem. To use initialize the Hunspell object with your dictionaries folder path and language (language match the dictionary file name).
dict = Hunspell.new("dictionaries", "en_US")
if dict.check('caribean') == false
suggestions = dict.suggest('caribean')
if (suggestions.size)
correction = suggestions.first # returns 'caribbean'
end
end
Vendoring for More Complex Projects
You can also vendor the library into your project by putting the tar built by the Vulcan server in the first step into a public accessible server such as Google Storage and then changing the Heroku build pack to download the tar on each instance startup.
heroku config:set BUILDPACK_URL=https://github.com/peterkeen/heroku-buildpack-vendorbinaries.git
The vendor build pack looks for a .vendor_urls file at the root level with HTTP links to the tar balls to install (needs to end in a new line to work).
http://commondatastorage.googleapis.com/developer.you.com/hunspell-heroku-1.3.tgz
Vendoring unpacks the tar into the root folder so the lib path for the Heroku settings would then just be "lib". heroku config:add LD_LIBRARY_PATH=lib
Unless I am mistaken or something has changed (I cannot find any evidence of this), you cannot install external native libraries on Heroku. If the library is not already installed (this is the case, I think, for ImageMagick, and perhaps others), you will not be able to use the gem.
Checkout this url: http://gems-summary.heroku.com/2011-07-19
It's freaking amazing how much support Heroku has for the gem community. So all you need to to is add the gem to your bundle since Hunspell is on rubygems, bundle install, and then deploy.
Gemfile
source 'http://rubygems.org'
gem 'rails', '3.0.5'
gem 'hunspell'
Then add to git:
git add .
git commit -m 'added hunspell'
Then bundle:
bundle
And deploy:
git push heroku
With Bundler, you should be able to install any gem. According to http://devcenter.heroku.com/articles/how-do-i-install-gems-for-my-app, "Almost any gem - even those with native dependencies - can be installed using Bundler. If there’s a specific gem that won’t install on Heroku, please submit a support ticket."
AFAIK, when your app is spun up, gems in the Gemfile are installed on-the-fly to the server your app is spun up to.
The Aspen stack has pre-installed gems, but you still should be able to add gems not pre-installed.
The bamboo stack has no pre-installed gems, so all gem dependencies must be declared explicitly. I believe that is the same for the Celadon stack.

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