The Rails 4 Way (2014)

Rails Essentials

Chances are you learned about Rails from watching beginner screencasts or studying our highly-rated companion in the Pro Ruby Series, the excellent Ruby on Rails Tutorial by Michael Hartl. Those resources will get you through the initial slope of the learning curve and on a trajectory towards serious productivity. But to continue making progress, it helps to know the tools that real Rails masters use every day.

Environmental Concerns

No, I’m not about to go off on a tangent about carbon credits and global warming. As a Rails pro, you’re going to spend a lot of time using the command line, so you might as well save yourself as much confusion and extra typing as possible. The following little tips and tricks should make your life easier and more enjoyable.

Operating System

While it is certainly possible to write Rails application on a Windows platform, and quite a few people do that, it is far from being optimal.

The fact is, your application is most probably going to run on a Linux server in production, and so, being able to install all the essential pieces locally is very important. Many of the gems that you might want to use will simply refuse to compile in a non-Unix environment.

Note that while your server is most probably runs Linux, you can quite easily use OS X as your development environment. At first glance this goes against the notion of running the same OS as the server, but fortunately most Rails developers use Apple machines for development and so historically they’ve made sure all relevant gems and software packages are available and compatible with those from the Linux environment. Practically all the gems that can be compiled on Linux will happily compile on OS X as well.

If you are stuck with Windows as your development machine it is usually better to run a Linux virtual machine to host the Ruby environment. Check out Vagrant for easy installation of development virtual machines.

Aliases

At minimum you should add aliases for starting your Rails server and console to your shell’s execution environment. Geoffrey Grosenbach suggests alias ss 'bundle exec rails server' and alias sc 'bundle exec rails console'.

discussion

Vitaly says…

You might want to add –debugger to your aliases if you always include a debugger gem in your applications

Essential Gems

Some gems are so valuable that (arguably) they should be a part of the core Rails distribution. However, because of the “less is more” philosophy of the core team, the Rails core distribution is actually shrinking, not growing.

The following section contains an alphabetical list of essential gems for the Rails pro to be aware of and use on a regular basis.

Better Errors

https://github.com/charliesome/better_errors

Better Errors replaces the standard Rails error page with a much better and more useful error page. It is also usable outside of Rails in any Rack app as Rack middleware.

Instead of a plain default error page, Better Errors will display a full interactive stack trace with source code inspection.

If you also include the companion binding_of_caller gem into your application Better Errors will be able to also let you inspect local and instance variables and even embed a full REPL into every stack frame of your error page backtrace. Of course you should only ever do that in a development environment.

To use it simply add the following to your Gemfile:

1 group :development do

2   gem "better_errors"

3   gem 'binding_of_caller'

4 end

Country Select

https://github.com/stefanpenner/country_select

This plugin, previously in Rails core, provides a simple way to get an HTML select tag with a list of countries. It lists countries as their full names and can optionally take a list of priority countries to display at the top of the options. It is English only and provides no i18n support.

Debugger

https://github.com/cldwalker/debugger

Debugger is a fork of a once-popular ruby-debug and ruby-debug19 gems. It will work with Ruby 1.8.7, and 1.9.x out of the box.

With the ruby-debug and ruby-debug19 gems, you had to choose one of them according to your Ruby version, whereas debugger will just work. Debugger is usually added to the :development and :test groups of your Gemfile.

Once installed you can simply add a call to debugger method in any place of your code to force the execution of the application to stop and start Debugger REPL.

Draper

https://github.com/drapergem/draper

As Rails applications grow, so can the complexity in the view layer. Some common symptoms for a complex view can include if/else conditions, multiple instance variables, and extensive chaining. The Draper gem provides an elegant solution to this problem by adding an object-oriented layer of presentation logic to your Rails application.

Instead of using a model instance variable directly in a view, using Draper, one can define a decorator instead. A decorator wraps an instance of a model with presentation-related logic. This allows you to encompass view specific logic for a model in one place. Not only is this a cleaner solution, it’s also easier to test, as Draper supports RSpec, MiniTest::Rails, and Test::Unit out of the box.

To get started, add the draper gem to your Gemfile and run bundle.

# Gemfile

gem 'draper'

To write a decorator for a model, create a new class in app/decorators which inherits from Draper::Decorator. For the purposes of our examples, assume we have an Active Record model Post that we wish to decorate.

1 # app/decorators/post_decorator.rb

2 classPostDecorator < Draper::Decorator

3   ...

4 end

Draper also comes with a Rails generator to automatically create a decorator for a given model.

$ rails generate decorator Post

Within a decorator, you can access the underlying model via the object method. Draper also provides access to Rails helpers within your decorators via the h method. To demonstrate, the method below renders an avatar if the post author has one.

1 # app/decorators/post_decorator.rb

2 classPostDecorator < Draper::Decorator

3   ...

4   def author_avatar

5     returnunless object.author.avatar?

6     h.image_tag(object.author.avatar, class: 'avatar')

7   end

8 end

To assign a decorator to an object, call the decorate method on a given object instance. This will automatically infer the decorator based on the object.

@post = Post.first.decorate

Alternatively, you can always explicitly instantiate a decorator yourself, supplying an instance of the decorated model as its argument.

@post = PostDecorator.new(Post.first)

Note that Draper also supports decoration on a collection. Each item in the collection will be decorated with the inferred decorator.

@posts = Posts.all.decorate

Kaminari

https://github.com/amatsuda/kaminari

One frequent need in a Rails application is paginating the database query results. For a long time the number one plugin to do it was will_paginate, but lately it is being replaced by a better alternative - “Kaminari”.

“A Scope & Engine based, clean, powerful, customizable and sophisticated paginator for Rails”

The interface is scope based. For example, to paginate a list of projects you can do this:

@projects = Project.page(params[:page])

One area where Kaminari shines is customization. If you need a custom markup for your pagination links you don’t need to edit obscure configuration files. Instead, you just edit html templates. To get the templates to customize run the following command:

$ rails g kaminari:views THEME

where THEME is ‘default’ or one of the themes from https://github.com/amatsuda/kaminari_themes.

Nested Form Fields

https://github.com/ncri/nested_form_fields

It’s super common to want to edit records along with their has_many associations on a single page.

This Rails gem helps creating forms for models with nested has_many associations and relies on jQuery to dynamically add and remove nested form fields without a page reload.

·        Works for arbitrarily deeply nested associations (tested up to 4 levels).

·        Works with form builders like simple_form.

·        Requires at least Ruby 1.9 and the Rails asset pipeline

To install, add nested_form_fields to your application’s Gemfile, run bundle and in your application.js file add:

//= require nested_form_fields

Usage is straightforward. The Readme file uses the following example (assuming that you have a User model with nested videos):

1 classUser < ActiveRecord::Base

2   has_many :videos

3   accepts_nested_attributes_for :videos, allow_destroy: true

4 end

Use the nested_fields_for helper inside your user form to add the video fields:

1 = form_for @user do |f|

2   = f.nested_fields_for :videos do |ff|

3     = ff.text_field :video_title

4     ..

Links to add and remove fields can be added using the add_nested_fields_link and remove_nested_fields_link helpers:

1 = form_for @user do |f|

2   = f.nested_fields_for :videos do |ff|

3     = ff.remove_nested_fields_link

4     = ff.text_field :video_title

5     ..

6   = f.add_nested_fields_link :videos

Note that remove_nested_fields_link needs to be called within the nested_fields_for call and add_nested_fields_link outside of it via the parent builder.

Pry and friends

Pry126 is a powerful alternative to the standard IRB shell for Ruby. It features syntax highlighting, a flexible plugin architecture, runtime invocation and source and documentation browsing.

The pry plugin pry-debugger127 adds navigation commands via the debugger (formerly ruby-debug) gem.

These two gems allow you to debug like a pro. Instead of debugger you use binding.pry as your breakpoint command.

Once the execution stops you have all the power of Pry, including syntax highlighted source listing, variables inspections, shell access etc.

To use Pry, just add the following two gems to your Gemfile development and test groups:

1 group :development, :test do

2   gem 'pry-rails'

3   gem 'pry-debugger'

4 end

Note that the standard debugger commands won’t work at a Pry prompt. Try help to see available commands.

tip

You add the following to ~/.pryrc file to make the n, c, s, f, and l work as before:

1 Pry.commands.alias_command 'l', 'whereami'

2 Pry.commands.alias_command 'c', 'continue'

3 Pry.commands.alias_command 'n', 'next'

4 Pry.commands.alias_command 's', 'step'

5 Pry.commands.alias_command 'f', 'finish'

Another useful pry plugin to be aware of is pry-rescue128. If an exception is raised and is not rescued, pry-rescue will automatically start a Pry session for you.

Rails Admin

https://github.com/sferik/rails_admin

Unlike some other frameworks, for example Django, Rails doesn’t come with a standard admin interface. Not to worry though, as there is no shortage of gems that provide this functionality.

Rails Admin is one of the better looking and functional ones.

It will allow you to display, create, edit, and delete records in the database, export data to CSV, JSON, or XML formats, manage your record associations and more.

To install it just add ‘rails_admin’ gem to your Gemfile, run bundle install and then run the provided generator:

$ rails g rails_admin:install

Rails Admin uses devise for authentication and will install it if it is not yet present in your project.

It is recommended to use a separate user model Admin in a separate table admins to authenticate access to the admin interface as it is less susceptible to accidental security exposure.

Remote debugger

In you are using Pow or any other web server that runs in a background, you can not directly use the debugger console. In this case remote debugger can be used.

Add the following code to the bottom of config/application.rb:

1 if ENV['RUBY_DEBUG_PORT']

2   Debugger.start_remote nil, ENV['RUBY_DEBUG_PORT'].to_i

3 end

Now you just need to start your server with RUBY_DEBUG_PORT environment variable set to a port value, like 25001, to enable remote debugger.

To connect to this server you use rdebug command line:

$ rdebug -c -p 25001

Simple Form

Generating complex forms by hand can be a very tedious and error prone process. A number of gems are available to help. One of the most popular lately is SimpleForm.

https://github.com/plataformatec/simple_form

“SimpleForm aims to be as flexible as possible while helping you with powerful components to create your forms.”

To add it to your project, first add the gem to your Gemfile:

gem 'simple_form'

Then run bundler to install it and a generator to install configuration file:

$ bundle install

$ rails g simple_form:install --bootstrap

The --bootstrap switch causes the generated markup to be Twitter Bootstrap compatible. Refer to the documentation for other markups supported out of the box.

State Machine

State machines can be a very powerful tool to describe, validate and maintain a complex object state. You can get by with using a couple of booleans for simple case, but it becomes too messy pretty soon. A proper state machine, on the other hand, can make even a quite complex case manageable.

The most popular state machine implementation at the time of writing is the state_machine gem. It has been described as the “gorilla of state machine gems” because it is packed with features like multiple state machines per class, event parallelization and namespacing, plus it includes adapters for ActiveRecord, DataMapper, Mongoid, MongoMapper and Sequel.

https://github.com/pluginaweek/state_machine

Be sure to check its state machine drawing functionality:

$ rake state_machine:draw CLASS=Project,Issue

The Graphiz-based visualizations can be invaluable when you have complicated state transitions.

Some people think that it is overkill for simple uses cases. A popular alternative is the lighter-weight Workflow gem, which is fairly lightweight at only 500 lines of code, and also features visualization capabilities.

https://github.com/geekq/workflow

The primary difference between the two libraries is that in Workflow, you define events inside of their related states. You possibility lose some reusability, but the definitions are somewhat easier to read and understand.

 1 classArticle

 2   include Workflow

 3

 4   workflow do

 5     state :new do

 6       event :submit, :transitions_to => :awaiting_review

 7     end

 8

 9     state :awaiting_review do

10       event :review, :transitions_to => :being_reviewed

11     end

12

13     state :being_reviewed do

14       event :accept, :transitions_to => :accepted

15       event :reject, :transitions_to => :rejected

16     end

17

18     state :accepted

19     state :rejected

20   end

21 end