Here at gap Intelligence, many of our applications are built using the Ruby on Rails framework. As a developer, I like Rails for its convention over configuration approach which gives it an accessible learning curve. Additionally, there's an abundance of free resources and online tutorials to help you get up and running quickly with Ruby on Rails. However, while there are many starter tutorials, few explore some of the more intermediate concepts that are common knowledge to Rails developers. Here are a few often used Rails tools and concepts that you should know about once you're ready to move past the basics:

Unsplash.com

Active Support #delegate Module

The delegate module provides a  delegate method that allows you to forward a class method to an associate object. It reduces the need to write extra methods when they can be leveraged from another related class.

For example, consider a Library class with a name attribute and a Book class:

class Library < ActiveRecord::Base
  has_many :books
end

class Book < ActiveRecord::Base
  belongs_to :library
end

To get the name of a library a book belongs to, you might use  book.library.name   or you could write a method:

class Book < ActiveRecord::Base
  belongs_to :library

  def library_name
    library.name
  end
end

Instead, you can simplify this by delegating a name method for Book to the associate Library class:

class Book < ActiveRecord::Base
  belongs_to :library

  delegate :name, to: :library, prefix: true
end

Now you can call   book.libary_name  without having to write additional methods.

Scopes

In Rails, scoping allows you to add a pre-defined class method for retrieving and querying objects. 

Consider again the Book class defined above with a method to retrieve all Books that have been checked out from a library: 

class Book < ActiveRecord::Base
  belongs_to :library

  delegate :name, to: :library, prefix: true

  def self.checked_out
    where(checked_out: true)
  end
end

Instead of defining a method for this query, you can simplify your class method into one line with scope:

class Book < ActiveRecord::Base
  belongs_to :library

  scope :checked_out -> { where(checked_out: true) }

  delegate :name, to: :library, prefix: true
end

You can even chain scopes together to execute one query!

Helpers

Helpers are modules that Rails will automatically include in your views for you. They’re useful for extracting code out of your views and keeping them DRY.

Using the Book class from above, let’s say you want to display whether a book was checked out, but you wanted to show “Available” or “Unavailable” instead of  true or false. Your view page might look like: 

<% if @book.checked_out %>
  <p> Available </p>
<% else %>
  <p> Unavailable</p>
<% end %>

If you want to display a book’s availability in across different views, this could get tedious. Instead, add a helper file for the Books class.

module BooksHelper

  def availability(book)
    return book.checked_out ? "Available" : "Unavailable"
  end

end

Now when you want to display a book's availability you can just use the helper method:

<p><%= availability(@book) %></p>

Concerns

Concerns are modules that allow you to share model roles and functionality across classes. It’s another great way to keep your code organized and keep your models from getting bulky. For example, continuing with our Book class from above, let’s add a Video class, and a Request class that has a basic polymorphic association with Books and Video: 

class Book < ActiveRecord::Base
  belongs_to :library
  has_many :requests as: :requestable

  def make_request
    requests.create(user: user, date_requested: Date.today)
  end
end

class Video < ActiveRecord::Base
  belongs_to :library
  has_many :requests as: :requestable

  def make_request
    requests.create(user: user, date_requested: Date.today)
  end
end

class Request < ActiveRecord::Base
  belongs_to :requestable, polymorphic: true
end

As you can see, both Book and Video use the same exact method to create a request. By moving the logic for requests into a concern, we can eliminate having repetitive methods and simply include the concern module.

module Requestable
  extend ActiveSupport::Concern

  included do
    has_many :requests as, :requestable
  end

  def make_request(user)
    requests.create(user: user, date_requested: Date.today)
  end
end

Now we can simplify our Book and Library class:

class Book < ActiveRecord::Base
  include Requestable

  belongs_to :library
end

class Video < ActiveRecord::Base
  include Requestable

  belongs_to :library
end

Delegate, Scopes, Helpers, and Concerns were all concepts that were on my (long) list of things I wish I'd known when I first dived into our Rails projects here at gap intelligence. All of them are useful Rails tools that will help you keep your project DRY, readable, and organized!

For more than 16 years, gap intelligence has served manufacturers and sellers by providing world-class services monitoring, reporting, and analyzing the 4Ps: prices, promotions, placements, and products. Email us at info@gapintelligence.com or call us at 619-574-1100 to learn more.