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.
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.
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:
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
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
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 :-).
class Engine < Rails::Engine
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.
//= 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
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
//= require_tree .
//= require image_zoomer with:
//= require image_zoomer_main
Integrating jQuery Plugin
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.
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.
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