Sonntag, 31. August 2014

Define polymorphic ActiveRecord model association!

If you feel yourself in the position that one of your ActiveRecord models belongs to more than one other model, you are facing a polymorphic association.
Polymorphism is the provision of a single interface to entities of different types.
A polymorphic association saves you from:
  1. multiple alike tables and models (and therefore logic repetition)
  2. extensive meaningless foreign key attributes
  3. abuse of STI pattern
The original codes reveals a simple association between Comment and Article:
class Comment < ActiveRecord::Base
  belongs_to :article
end

class Article < ActiveRecord::Base
  has_many :comments
end
If also the Author should be commentable, adding a second foreign key attribute author_id is not a good choice (one of the foreign key attribute is meaningless in every case and it is horrible to validate both associations not interfering each other).
Adding a second model e.g. AuthorComment also is no option for duplication reasons.
On the other hand converting the association to a polymorphic association is fairly easy:
1.) rename the foreign key attribute article_id to the more abstract commentable_id and migrate it:
rename_column :comments, :article_id, :commentable_id
2.) add a new attribute commentable_type and migrate it:
add_column :comments, :commentable_type, :string
The attribute commentable_type is for defining the name of the associated class like Article and Author as string. It should always end with '_type'. Otherwise you have to configure it by the option :foreign_type on the belongs_to association.
3.) the model is ready for the polymorphic association:
class Comment < ActiveRecord::Base
  belongs_to :commentable,
    polymorphic: true
end
4.) multiple models can use it:
class Article < ActiveRecord::Base
  has_many :comments,
    as: :commentable
end

class Author < ActiveRecord::Base
  has_many :comments,
    as: :commentable
end
The models are based on the ERM:

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17

Sonntag, 24. August 2014

Singularize resource routes, if it is singular!

In most cases plural routes (read Simple RESTful Ruby on Rails routes) are needed to deal with the resources. But sometimes it makes sense to have only a singular resource routing.
Whenever a resource is singular (like Singletons) or singular in the current context, its routes should be singular as well. Reasons are:
  1. Expressiveness (to express the resource is singular)
  2. Less routes (singular resources have no index route for returning collections)
  3. Resource ID can be hidden (the object can be found anyway)
For example the original plural routes to the users profile (routes.rb):
resources :profiles, except: [:index, :destroy]
for the model:
class Profile < ActiveRecord::Base
  belongs_to :user
  validates :user, presence: true
end
give access to the RESTful controller (profiles_controller.rb):
class ProfilesController < ApplicationController
  def show
    @profile = Profile.find params[:id]
  end

  def new
    @profile = Profile.new user_id: user.id
  end

  def create
    @profile = Profile.new user_id: user.id
    @profile.attributes = params[:profile]
    render(action: :new) unless @profile.save
  end

  def edit
    @profile = Profile.find params[:id]
  end

  def update
    @profile = Profile.find params[:id]
    @profile.attributes = params[:profile]
    render(action: :edit) unless @profile.save
  end
private
  def user
    @user = User.find session[:user_id]
  end
end
in the view:
  <%= link_to 'Profile', profiles_path(@user.profile) %>
A user can have only one profile. It can created, updated, but not deleted. After the user accounted, the User object is always present. That is why the Profile ID is not required to be parameterized.

Refactoring starts with singularizing the routes (routes.rb):
resource :profile, except: :destroy
to the refactored controller (profiles_controller.rb):
class ProfilesController < ApplicationController
  def show
    @profile = user.profile
  end

  def new
    @profile = user.build_profile
  end

  def create
    @profile = user.build_profile
    @profile.attributes = params[:profile]
    render(action: :new) unless @profile.save
  end

  def edit
    @profile = user.profile
  end

  def update
    @profile = user.profile
    @profile.attributes = params[:profile]
    render(action: :edit) unless @profile.save
  end
private
  def user
    @user = User.find session[:user_id]
  end
end
and the refactored link in the view:
  <%= link_to 'Profile', profile_path %>
Please note the ProfilesController keeps being pluralized.
All its 6 standard routes are listed:
Path HTTP verb Action Behaviour
/profile POST create Creates a new profile
/profile/new GET new Returns the form a new profile
/profile GET show Displays the profile for the accounted user
/profile PUT update Updates the profile for the accounted user
/profile/edit GET edit Returns the form for editing profile for the accounted user
/profile DELETE destroy Deletes the profile for the accounted user (since the route is needless, it was removed from the standard routes)
Please compare the generated singular routes with their plural companions. Concluding singular resources simplify routing in dedicated cases.
Further articles of interest:

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17

Sonntag, 17. August 2014

Let it walk like a duck!

Please, do not let the title irritate you. It is just an controversial introduction to duck typing in Ruby, backed by the well-know saying:
"When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck."
Duck types are public interfaces that are not tied to any specific class. They are about the object's methods and properties, rather that its inheritance from a certain class. In a nutshell:
Behaviour over class membership
Following that pattern helps to improve:
  1. readability (less code for all message sender)
  2. add enormous flexibility
  3. reduces class coupling and therefore increases maintainability
The following original code contains 3 classes, each offering one getter method (Ingredient#name, Food#brand and Product#brand) returning a String.
class Drug
  attr_accessor :dope, :brand
end

class Food
  attr_accessor :ingredients
  def labeling
    ingredients.map { |ingredient| ingredient.name }.join(', ')
  end
end

class Clothing
  attr_accessor :name
end
and a Bill class for printing out:
class Bill
  def print_name product
    return puts "#{product.brand} (#{product.dope})" if product.respond_to? :dope
    return puts product.labeling if product.respond_to? :labeling
    puts product.name
  end
end
The Bill#print_name can be refactored by also duck typing the 3 classes:
class Drug
  attr_accessor :dope, :brand
  def name
    "#{product.brand} (#{product.dope})"
  end
end

class Food
  attr_accessor :ingredients
  def labeling
    ingredients.map { |ingredient| ingredient.name }.join(', ')
  end
  alias_method :name, :labeling
end

class Clothing
  attr_accessor :name
end
All 3 classes now respond to name and can called in Bill#print_name like:
class Bill
  def print_name product
    puts product.name
  end
end
Further articles of interest:

Supported by Ruby 2.1.1

Sonntag, 10. August 2014

Do not break the law of Demeter!

The definition of the law of Demeter also known as the principle of least knowledge is:
A given object should assume as little as possible about the structure or properties of anything else (including its subcomponents).
It also can be described by:
  1. Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
  2. Each unit should only talk to its friends; don't talk to strangers.
  3. Only talk to your immediate friends.
Given the following example with 3 classes (ActiveRecord models):
class Category < ActiveRecord::Base
  attr_accessible :name
end

class Food < ActiveRecord::Base
  attr_accessible :name, :category_id
  belongs_to :category
end

class Recipe < ActiveRecord::Base
  attr_accessible :name, :food_id
  belongs_to :food
end
and accessing the recipes category name in the ERB template in that way:
Recipe: <%= @recipe.name %>
Recipe food category: <%= @recipe.food.category.name if @recipe.food and @recipe.food.category %>
is definitely a bad practice for various reasons:
  1. The Recipe object has not only to know about its associated Food object, but also about how the food object is associated to the Category object.
  2. The path gets longer the more objects are involved and the more the Recipe object has to know about other objects associations.
  3. An object during the path could be nil, and hence the path could be broken. Therefore a long security condition statement is needed every time the path is gone.
  4. Repeating the security condition everywhere the path was used, is hard to maintain, if even only one association changed.
Those points mean that the law of Demeter was broken.
It can be fixed by hiding the knowledge about the directly associated object in an instance method like:
class Category < ActiveRecord::Base
  attr_accessible :name
end

class Food < ActiveRecord::Base
  attr_accessible :name, :category_id
  belongs_to :category

  def category_name
    category.name  if category
  end
end

class Recipe < ActiveRecord::Base
  attr_accessible :name, :food_id
  belongs_to :food

  def food_category_name
    food.category_name if food
  end
end
The Recipe object only knows about its associated Food object and how to get its category_name, without knowing HOW the Food object gets the category_name. But the Food object just knows how to get the Category name. The knowledge was appropriately hidden and can accessed like:
Recipe: <%= @recipe.name %>
Recipe food category: <%= @recipe.food_category_name %>
Well, Ruby on Rails is handy enough to offer some syntactic sugar for delegating methods with the help of Module#delegate. That is why the models look better delegating the Category name:
class Category < ActiveRecord::Base
  attr_accessible :name
end

class Food < ActiveRecord::Base
  attr_accessible :name, :category_id
  belongs_to :category

  delegate :name, to: :category, prefix: true, allow_nil: true
end

class Recipe < ActiveRecord::Base
  attr_accessible :name, :food_id
  belongs_to :food

  delegate :category_name, to: :food, prefix: true, allow_nil: true
end
The detailed options can be read in the Module#delegate API documentation. The ERB template need not to be changed:
Recipe: <%= @recipe.name %>
Recipe food category: <%= @recipe.food_category_name %>

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17

Sonntag, 3. August 2014

Stringify your ActiveRecord model objects!

The view in a Ruby on Rails project very often is about string representations of the stored ActiveRecord model objects. For example:
class Food < ActiveRecord::Base
  validates :name, presence: true
  belongs_to :category
end

class Category < ActiveRecord::Base
  validates :name, presence: true
  attr_accessible: name
end
and in the view the objects (food and its category) are represented by their name attribute:
Food name: <%= @food.name %>
Food category: <%= @food.category.name unless @food.category.nil? %>
That works actually and the generated HTML could look like:
Food name: Apple Cider Cookie
Food category: Sweets
The ERB templating in Ruby on Rails sends the to_s message to the embedded result anyway. So something like that:
Food name: <%= @food %>
Food category: <%= @food.category %>
would not throw an exception, if the category was nil (since nil.to_s returns a blank string) and send the ActiveRecord::Base#to_s to the objects. Please note, not only the methods name are left out, but also the unless condition can be omitted, which looks much nicer in the view. At that point the result looks like:
Food name: #<Food:0x000000070c5010>
Food category: #<Category:0x0000000153b708>
It is the natural string representation of ActiveRecord model objects but does not serve any purpose. Overwriting ActiveRecord::Base#to_s in particular models is absolutely reasonable:
class Food < ActiveRecord::Base
  validates :name, presence: true
  belongs_to :category
  def to_s
    name
  end
end

class Category < ActiveRecord::Base
  validates :name, presence: true
  attr_accessible: name
  def to_s
    name
  end
end
and in the ERB template:
Food name: <%= @food %>
Food category: <%= @food.category %>
results in:
Food name: Apple Cider Cookie
Food category: Sweets
The big plus for overwriting ActiveRecord::Base#to_s is that the typical string representation for the model objects can be defined and especially in the case of more complex string representations it is absolutely reasonable.

Supported by Ruby 2.1.1 and Ruby on Rails 3.2.17