A Gem for Every Occasion: 11 Great Rails Libraries We Use on Every Project

a-gem-for-every-occasion-11-great-ruby-libraries-we-use-on-every-project-0

As you work with your favorite programming language, you often look for tools to make your job easier. In the Ruby world, these tools (gems) are created on a daily basis, but only some of them are good enough to win our hearts.

Here are some of the core gems that have a special place in all of our Gemfiles. Some of them help with debugging code, others provide certain functionality like authentication. That’s useful in almost any project. In the end, they all help us work faster and produce quality software.

title
better_errors

2. devise

Whether you need simple HTTP authentication, or you’re looking for some complex Facebook and Google+ login system, this authentication solution is great and it will significantly speed up your work. It’s built on top of the Rails MVC stack and its modular architecture allows you to pick what you need.

	class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :confirmable, :recoverable, stretches: 20
end

The successor of the abandoned cancan project, this authorization gem lets you define what a user can do on your website by using abilities defined in a single place.

	class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # guest user (not logged in)
    if user.admin?
      can :manage, :all
    else
      can :read, :all
    end
  end
end

In newer projects we started experimenting with pundit. It is faster, more modular and it wont bloat a single file.

We find this gem to be the best when you need to extract some longer-running actions (e.g., sending newsletters to a large number of users) into a background task. You can reuse methods from your models, or you can create complex classes for all your background task needs. With delayed_job, even progress bars are possible in Ruby on Rails.

	# without delayed_job
Notifier.signup(@user).deliver

# with delayed_job
Notifier.delay.signup(@user)

# with delayed_job running at a specific time
Notifier.delay(run_at: 5.minutes.from_now).signup(@user)

It’s quite annoying to set up email delivery in a development environment, and that’s where Letter Opener is great. It displays the email in your browser so you can easily inspect it, click any links (e.g., account confirmation) and not spam your email account with tons of test emails.

letter_opnener demo

6. mina

Easily configured, this gem allows you to do fast remote deployments of you website, as multiple environments are supported and all the work is done in only one SSH session (compared to Capistrano’s multiple SSH sessions). For more info, check out this article about Mina, written by my colleague Gabrijel Škoro.

	 
➜  project git:(master) ✗ mina production deploy
-----> Creating a temporary build path        
-----> Fetching new git commits        
-----> Using git branch ’master’        
       Cloning into ’.’... 
       done. 
-----> Using this git commit        

       user (0695b54): 
       > increase credits after manual order update 

-----> Symlinking shared paths        
-----> Installing gem dependencies using Bundler        
       # list of gems ommited
       Your bundle is complete! 
       Gems in the groups development and test were not installed. 
       It was installed into ./vendor/bundle 
-----> DB schema unchanged; skipping DB migration        
-----> Skipping asset precompilation        
-----> Cleaning up old releases (keeping 5)        
-----> Build finished        
-----> Moving build to releases/307        
-----> Updating the current symlink        
-----> Launching        
-----> Symlink system to shared        
-----> Restarting application        
-----> Done. Deployed v307        
       Elapsed time: 2.00 seconds

You often have to deal with attachments that need to be processed in various ways. With paperclip, that becomes quite simple (with the support of ImageMagick) and allows you all sorts of validations and transformations, providing support for customizations as well.

	class User < ActiveRecord::Base
  has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
  validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
end

If you feel adventurous, you can try refile from the creators of carrierwave.

Plain Rails generated forms (and related helpers) aren’t really that helpful when you’re designing a great user interface, which is essential for every website. This is where Simple Form saves the day with its powerful yet simple DSL.

	= simple_form_for @user do |f|
  = f.input :username, label: ’Your username please’
  = f.input :password, hint: ’No special characters.’
  = f.input :email, placeholder: ’user@domain.com’
  = f.input :remember_me, inline_label: ’Yes, remember me’
  = f.button :submit

If you’re doing testing (and you should!), this gem helps you to easily integrate rspec framework into your Rails project by generating the necessary configuration files and spec helpers.

	require "spec_helper"

describe User do
  it "orders by last name" do
    lindeman = User.create!(first_name: "Andy", last_name: "Lindeman")
    chelimsky = User.create!(first_name: "David", last_name: "Chelimsky")

    expect(User.ordered_by_last_name).to eq([chelimsky, lindeman])
  end
end

When testing your projects, you need data. The best way to generate test data is to use a factory generator. The factory_girl_rails gem helps you to easily integrate Factory Girl, our favorite factory generator, into your Rails projects.

	# spec/factories/user.rb
FactoryGirl.define do
  factory :user do
    first_name "Andy"
    last_name  "Lindeman"
  end
end

# spec/models/user_spec.rb
require "spec_helper"

describe User do
  it "orders by last name" do
    lindeman = create(:user)
    chelimsky = create(:user, first_name: "David", last_name: "Chelimsky")

    expect(User.ordered_by_last_name).to eq([chelimsky, lindeman])
  end
end

Debug your code like a champ. With pry, you can see what went wrong in any part of your Rails project, in your tests, third-party gems, and it can even be used in the Rails console.

	Started GET "/" for 127.0.0.1 at 2014-10-24 09:57:12 +0200
Processing by HomeController#index as HTML
  User Load (0.5ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 1  ORDER BY "users"."id" ASC LIMIT 1

From: /Users/stef/dev/gluposti/blogs/app/controllers/home_controller.rb @ line 4 HomeController#index:

    2: def index
    3:   @user = current_user
 => 4:   binding.pry
    5: end

[1] pry(#<HomeController>)> current_user
=> #<User id: 1, email: "admin@infinum.co", encrypted_password: "$2a$10$AR/1ZnYJS5hqFNtDzx3ZGuGlRlinktNPebsp6Ye5ENn...", reset_password_token: "5e116a7fd356c11cccfcf27ab981e19b5a756dd7c6f2bd64ba...", reset_password_sent_at: "2014-10-24 07:32:34", remember_created_at: nil, sign_in_count: 2, current_sign_in_at: "2014-10-24 07:57:12", last_sign_in_at: "2014-10-24 07:25:25", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2014-10-24 07:25:25", updated_at: "2014-10-24 07:57:12">
[2] pry(#<HomeController>)> cd @user
[3] pry(#<User>):1> email
=> "admin@infinum.co"