Posts tagged with "gems"

We probably don't need to sing the praises of open source software to anyone. Of course, closed source has its place too. Not all code can or should be shared, whether it's proprietary or simply not ready to share yet.

Github has become our repository of choice for both open and closed source code. These days, much of our code is Ruby and so many of our libraries get packaged as gems. We've found Jeweler to be the easiest way to create those gems and Bundler to be the best way to manage them in projects.

This article describes how we use Jeweler, Github and Bundler to create, host and manage our private gems.

Create a new repository

Start by creating a new private repository at Github (you'll need a paid account to create private repositories). Optionally add collaborators.

github_repo

Create a Gem with Jeweler

Install the jeweler gem:

$ gem install jeweler

Create your gem:

$ jeweler jeweler_test

Configure the remote repository for your gem:

$ cd jeweler_test
$ git remote rm origin
$ git remote add origin git@github.com:YOUR_ACCOUNT_HERE/jeweler_test.git

Check out the options that Jeweler provides:

$ rake -T

rake build               # Build gem into pkg/
rake clobber_rcov        # Remove rcov products for rcov
rake clobber_rdoc        # Remove rdoc products
rake console[script]     # Start IRB with all runtime dependencies loaded
rake gemcutter:release   # Release gem to Gemcutter
rake gemspec             # Generate and validate gemspec
rake gemspec:debug       # Display the gemspec for debugging purposes, as ...
rake gemspec:generate    # Regenreate the gemspec on the filesystem
rake gemspec:release     # Regenerate and validate gemspec, and then commi...
rake gemspec:validate    # Validates the gemspec on the filesystem
rake git:release         # Tag and push release to git.
rake install             # Build and install gem using `gem install`
rake rcov                # Analyze code coverage with tests
rake rdoc                # Build the rdoc HTML Files
rake release             # Release gem
rake rerdoc              # Force a rebuild of the RDOC files
rake test                # Run tests
rake version             # Displays the current version
rake version:bump:major  # Bump the major version by 1
rake version:bump:minor  # Bump the a minor version by 1
rake version:bump:patch  # Bump the patch version by 1
rake version:write       # Writes out an explicit version.

We don't want to mistakenly release our private gem to Gemcutter, so comment out the following line in your Rakefile:

# Jeweler::RubygemsDotOrgTasks.new

While you're editing your Rakefile, fill out your gem's details such as summary, description, etc. (look for the TODOs). When using Jeweler, you should edit these details in your Rakefile and not your gemspec file, which gets auto-generated.

Running rake -T again should confirm that the gemcutter:release task is now missing. Without this task, the release task will release to Github but not Gemcutter.

Let's version our gem, create a gemspec (using the details from the Rakefile) and then push an initial release to Github:

$ rake version:write MAJOR=0 MINOR=1 PATCH=0
$ rake gemspec
$ git add -A
$ git commit -a -m "initial commit"
$ rake release

The process is very similar for future releases:

$ rake version:bump:patch
$ rake gemspec
$ git commit -a -m "made some changes"
$ rake release

Include your gem with Bundler

Bundler makes it easy to include your gem in your projects. Simply add the following to your Gemfile:

gem 'jeweler_test', :git => 'git@github.com:YOUR_ACCOUNT_HERE/jeweler_test.git'

Do you want a specific version of your gem? Specify one with :tag:

gem 'jeweler_test', :git => 'git@github.com:YOUR_ACCOUNT_HERE/jeweler_test.git', :tag => 'v0.1.0'

Bundler will pull your source, build your gem and install it with a simple call to:

bundle install

That's it! Your private gem should now be bundled with your project.

Open sourcing your gem later

If you decide to open source your gem later:

  1. Change its visibility to public in Github;
  2. Uncomment Jeweler::RubygemsDotOrgTasks.new from your gem's Rakefile; and,
  3. rake release will now release your gem to Github and Gemcutter simultaneously.

Update 3/21: John McAliley has written up a great tip for using two sources for a gem in different environments with Bundler at his "Cowboy Coded" blog. This approach works well for developing gems alongside Rails apps.

Update 7/22: Thanks to dwradcliffe's comment below, the process of removing the gemcutter:release task has been greatly simplified.

Tame Rails Email Dragons with Mailhopper

Posted by Dan Gebhardt on Sep 07, 2011

There are plenty of pitfalls lurking in the seemingly straightforward topic of email processing in Rails.

Let's lift a few rocks to find where there be dragons...

Synchronous Mail Delivery

Synchronous Mail Processing

Synchronous mail delivery, the default in Rails, seems so simple. A controller responds to a request by generating an email through a mailer. The mailer in turn hands off the email to a mail server for delivery to the user.

No problem, right?

Synchronous Mail Processing with Dragons

Unfortunately, this scenario is rife with potential problems. Synchronous mail processing requires a successful round trip to your SMTP or sendmail server in order to respond to your users' requests. The first danger is that users might fall asleep while waiting for some signs of life from your application. Greater dangers lurk along the path from your mailer to your mail server. Your mail server may be down or inaccessible, or perhaps you've been blacklisted (mistakenly, of course). Regardless, the best your users can hope for is an error message telling them that their message couldn't be sent. And as the developer, you may need to hunt through the logs to try to find and resend their missing email. Ugh.

Asynchronous Mail Delivery

Asynchronous Mail Processing

By sending email asynchronously, you can keep responses snappy and insulate your users from the problems of synchronous mail processing. As you would expect, there are already some asynchronous email solutions for Rails. DelayedJob adds a custom "delay()" method to mailers that can be used instead of "deliver()". If you use Resque to process background jobs, check out ResqueMailer. Both solutions queue mail jobs to be performed later, without delaying a response to the user. Queued jobs will continue to be retried until successful, thereby minimizing problems caused by a temporarily inaccessible mail server.

Sounds like the right answer, doesn't it?

Asynchronous Mail Processing with Dragons

While asynchronous mail delivery usually works well, there are still a few gotchas. Since both the generation and delivery of messages is queued, it is possible that the data required to generate your messages could change from the time the message gets queued to the time it is generated. Therefore, you'll want to pass ids of objects instead of the objects themselves to mailer methods. You'll also need to verify that the objects still exist and are in the required state for the requested message. Imagine that a day passes without the queue being processed: you'll either be glad that you put the work in up front to ensure that your mailer methods handle all possible exceptions, or you'll simply delete your mail queue and apologize profusely to your users (which you should probably do after a day of downtime anyway).

Mail Delivery with Mailhopper

Mail Processing with Mailhopper

Keeping in mind the problems inherent in both synchronous and asynchronous mail delivery, we devised a new blended approach. Mailhopper acts as a delivery agent that synchronously generates messages and stores their content in your database. A separate gem, DelayedMailhopper, adds those messages to the DelayedJob queue for asynchronous delivery via a delivery agent such as SMTP or sendmail.

By synchronously generating messages, including their full content and headers, Mailhopper eliminates the need to carefully craft your mailer methods to function asynchronously. Want to pass an object instead of an id? Go for it! You can safely assume that your mailer methods are called as part of a synchronous request.

By using DelayedMailhopper to deliver messages asynchronously, the speed and reliability issues of synchronous mailing are avoided.

Because Mailhopper acts as a delivery agent, there are no special methods that must be called to use it for delivering messages. Instead, you can define Mailhopper as the default agent for a mailer method, for a whole mailer, or even your entire application.

And by storing messages in a separate table (called Emails by default), the full contents of those messages are archived automatically. You can optionally run a separate background process to purge messages after they've been sent or reached a certain age. Or you can choose to keep them in your database permanently. It's pretty handy for customer support to have an admin interface which can pull up all the emails sent to a particular address.

Both Mailhopper and DelayedMailhopper were built as Engines that are compatible with Rails 3.1+. If you'd like to try them out, please see the installation and configuration instructions in the README files. If you'd like to use Mailhopper with Resque, there's an obvious opportunity to write "ResqueMailhopper", using DelayedMailhopper as a starting point (please let us know if you tackle this).

Happy mailing!

Mailhopper Dragon