Ruby
Article

Create a Ruby Gem for a jQuery Plugin: Basics

By Imran Latif

Screenshot 2014-10-12 11.39.13

Rails consists of features that no other framework in web development space is providing at the moment. With each release, its feature set is getting stronger and stronger. Whether it’s about integrating support for streaming into the core framework, or Russian Doll Caching, or the ease of managing dependencies using Bundler, Rails has always proven itself as pioneer in introducing new and emerging concepts in web development.

Rails is built in Ruby and one can truly say that Rails is all about Ruby and Ruby is all about gems. Ruby code is primarily composed of gems, which is equivalent to libraries in other languages’ perspectives. Rails is, itself, a Ruby gem. Gems provide a clean and elegant way to organize related code. Creating and separating related code in proper gems is the first step in achieving modularity in your codebases.

In this post, we will create a gem from scratch. The gem we are building is based on a jQuery plugin. You might be wondering: Why bother developing a gem for jQuery plugin when we can simply grab it’s source code and start using it? The reason is Rails. Rails provides developers with a way to do things in a systematic way and that’s part of the beauty that separates it from other frameworks. By developing a gem, we will no longer have to ask the developer to manually write JavaScript code. Instead, our gem will do the right thing automatically, thus saving developer time.

The jQuery plugin for our gem is called image_zoomer. This plugin provides a zoom effect for images without requiring extra images. The GitHub repo has a demo, so you can get an idea about what it does. Our goal is to provide a systematic, “Rails” way, so that developers just have to install our gem and they are done. All setup needed by the plugin will be handled by our gem. If you don’t want to go through all steps and want to leap to the end, visit the image_zoomer_rb repository. For the rest of you, let’s get started.

Gem Skeleton

First, install latest version of Ruby, which is is 2.1.2 as of this writing. Also, install the latest version of Rails so we can test the gem as it’s being built.

Bundler makes it quite easy to not only install and manage dependencies but also create a gem’s basic skeleton. Use the following command:

bundle gem name_of_gem

Naming a gem is not hard in Ruby, but you should do so deliberately. There are some official guidelines that every gem author should read before naming a gem. Our gem will be called image_zoomer so it correlatest with the jQuery plugin. Now, create the gem skeleton:

bundle gem image_zoomer

The output of the above command will be something like:

create image_zoomer/Gemfile
create image_zoomer/Rakefile
create image_zoomer/LICENSE.txt
create image_zoomer/README.md
create image_zoomer/.gitignore
create image_zoomer/image_zoomer.gemspec
create image_zoomer/lib/image_zoomer.rb
create image_zoomer/lib/image_zoomer/version.rb
Initializing git repo in /Users/imran/Desktop/work/gem_creation/sitepoint/image_zoomer

image_zoomer.gemspec is the file which contains the meta information about our gem in a predefined way. Check this reference guide for detailed information about each available property. Bundler has populated this file with default values, which can be updated as needed. This file is also used to define gem’s dependencies. Bundler has filled it with bundler and rake. Since our gem only depends upon Rails and a jQuery plugin, don’t need to include anything else.

Go ahead and change other fields, like authors and email, so that the world knows who created this gem.

The Gemfile is used by Bundler to install and manage our dependencies, which you likely already knew. However, I just said that image_zoomer.gemspec is used to manage our gem dependencies. Bundler has done something clever here.

Opening the Gemfile, you’ll notice there is a call to gemspec. The Gemfile is automatically referencing the image_zoomer.gemspec file and, hence, Bundler will manage dependencies as defined in the gemspec.

The Rakefile contains rake tasks related to gem creation, installation, and distribution.

LICENSE.txt contains an MIT license, automatically generated for us. You can replace it with the licensing scheme of choice to indicate permissions and restrictions you are placing on the users of the gem.

README.md contains installation and usage related information. It is filled with a default structure defined by Bundler. Every gem author should update it according to his requirements.

.gitignore is used by Git to ignore files.

lib/image_zoomer/ is the preferred and community accepted way of defining Ruby classes and modules needed for our gem to operate. You will see this pattern in every Ruby gem.

lib/image_zoomer.rb is the base file of the gem, normally used to define the base module and require modules and classes defined in lib/image_zoomer/. Since our gem name is image_zoomer, a module ImageZoomer is automatically created for us.

lib/image_zoomer/version.rb contains the version of our gem. It is first iteration of our gem, so 0.0.1 seems absolutely fine.

Create a Sample App

We have created a basic skeleton for our gem. It’s best to start testing it with a dummy Rails app to find errors upfront. To create a sample Rails app, type (NOTE: Do this OUTSIDE of your gem directory):

rails new image_zoomer_app

Create a controller and view, resulting in a place to test the things offered by our gem.

rails generate controller site index

This will create a controller site with a method index. The routes.rb will be automatically updated, too. Include our gem in this Rails application. Open up the Gemfile and type:

gem 'image_zoomer', '0.0.1', path: '/Users/imran/Desktop/work/gem_creation/sitepoint/image_zoomer/'

Bundler provides an easy way to include local gems. We have specified name of our gem, version, and absolute path. Your path will be different, of course. You can skip the version, but it is best to keep it there because, without it, local .gem files can create issues.

Go ahead and open app/views/site/index.html.erb , delete the auto-generated content it already have and paste following code.

<%= ImageZoomer::VERSION %>

Start the server and visit http://localhost:3000/site/index. You’ll see 0.0.1 displayed on the page. Cool!. We have just created a small gem and used it in a Rails app. You must be feeling accomplished, but the journey has just started :-).

Include JavaScript Assets

Since we are creating a gem for a jQuery plugin, the gem is completely useless without the file for said jQuery plugin. Create a directory called app/assets/javascripts in the gem’s root directory. Go to the image_zoomer plugin GitHub page, clone or download the repo, and grab image_zoomer.js and place it in the new app/assets/javascripts directory.

Thanks to the Rails core team, including JavaScript and other assets is quite easy. Simply create a file named engine.rb in the lib/image_zoomer directory and paste following code:

module ImageZoomer
  class Engine < Rails::Engine
  end
end

According to Rails, in order to include assets from a gem/engine into a Rails app, class called Engine subclased from Rails::Engine must exist. Rails will take care of the rest.

Return to the dummy Rails application and open app/assets/javascripts/application.js. Append the following line:

//= require image_zoomer

This will include the jQuery plugin in our Rails app’s assets. Restart your server, refresh the page and you will get an error. Oops!. This isn’t what we expected. There is an ugly error about how the Rails Asset Pipeline is unable to locate image_zoomer. Have we missed something? Yes, we have. Remember, we created a file engine.rb in our gem a few moments ago, but we forgot to require it. Without requiring, the code inside this file will never execute. Open up lib/image_zoomer.rb in the gem and paste the following line after the first require statement.

require "image_zoomer/engine"

This will include all the assets under app/assets/ in the same way we include assets from our Rails app. Restart your web server and refresh the browser. This time you will not see any errors. Also right-click anywhere in the browser and choose view source. You’ll see a script tag referencing image_zoomer.js.

We have only used one JavaScript file from our gem. If there were other JavaScript files, we’d have to mention each one app/assets/javascripts/application.js. Don’t you think that is a bit weird? Yes, it is. Don’t worry, there’s a better way.

Sprockets (the gem behind the Rails Asset Pipeline) has a directive to include all files under a directory. Create a file image_zoomer_main.js under app/assets/javascripts in our gem and paste the following code:

//= require_tree .

That tells the Asset Pipeline to recursively require all files in all subdirectories of the specified path. The dot (‘.’) means the current path, so all files under the current path will be included by the Asset Pipeline. Now, open app/assets/javascripts/application.js in your Rails app and replace //= require image_zoomer with:

//= require image_zoomer_main

Restart the web server, refresh the browser and view page source again. Observe that both JavaScript files from the gem are in the response. This is great, as now we don’t have to worry about managing each JavaScript file individually.

Integrating jQuery Plugin

With the JavaScript assets being included from our gem, it’s time to get real by integrating the jQuery plugin with the Rails app. image_zoomer‘s usage on GitHub is pretty straightforward. Let’s include this in our gem. We will not make any changes to image_zoomer.js, because future updates can become difficult to manage. Instead, let’s create a separate file to hold code for initializing the plugin.

But first, include an image on our web page. Open app/views/site/index.html.erb and replace everything with:

<%= image_tag("test.jpg"); %>

You can replace test.jpg with the name of any (reasonably sized, meaning, big enough to merit zooming) image you have. Be sure to place it in the app/assets/images directory in our Rails app. Refresh your browser and you will see an image. Hovering over the image will not reveal any zooming effect for the moment.

Create a file image_zoomer_initializer.js under app/assets/javascripts in our gem with:

$(function() {
  $(".image_zoomer").each(function() {
    $(this).image_zoomer();
  });
});

We have used .image_zoomer CSS selector as our base selector, so any image that has the image_zoomer CSS class will receive the zoom effect provided by image_zoomer. Open app/views/site/index.html.erb and update the code so it looks like this:

<%= image_tag("test.jpg", :class => "image_zoomer"); %>

We are applying the CSS class to the image and have the initializing code in image_zoomer_initializer.js.

Let’s see it in action. Refresh your browser and if everything is setup fine you should see image zooming in action.

Basics Complete

We have implemented a systematic way of applying zooming effects on images in Rails apps. Instead of asking users to manually download certain assets, etc., they simply need to install our gem, update app/assets/javascripts/application.js, and add the image_zoomer CSS class to images we want to get zoom effect.

You should feel pretty good about yourself, because you have just learned how to automate things by building a gem.

In the next article, things get a bit more advanced:

  • How to create a custom helper for our gem
  • How to provide default settings needed by the jQuery plugin
  • How to give users the ability to override default settings by using Rails initializers
  • How to resolve issues of assets caching
  • How to bundle and release the gem
  • Rohit D

    Nice Article! …. Waiting for next part

  • ggsp
  • http://blog.thiagobelem.net/ Thiago Belem

    Please use something like https://rails-assets.org/, no need to create a gem only for including some jQuery plugins! :)

    • Imran Latif

      @Thiago: [Author here] You are quite right but we have to see Rails community’s preferred way for this thing. Presently Rails community is fine with having gems for jQuery plugins, one best example of this is jquery gem itself. So lets see when Rails community accepts Rails Assets as the way to go and on that day developers will definitely stop writing gems for jQuery plugins :-).

      Please do read second part of this article as well which has covered some advanced concepts http://www.sitepoint.com/create-ruby-gem-jquery-plugin-advanced/. :-)

      Thanks.

  • Bala Paranj

    //= require image_zoomer_main does not work in Rails 5. I had to include the files manually in the Rails 5 app:

    //= require jquery
    //= require jquery_ujs
    //= require turbolinks
    //= require_tree .
    //= require image_zoomer
    //= require image_zoomer_initializer

    Any ideas how to fix it?

  • Bala Paranj

    The customization of height and width discussed in the second part of this article is not working in Rails 5.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Ruby, once a week, for free.