Examples of Inversion of Control

In the post Inversion of Control (IoC), I described what was. Here I describe several examples of Inversion of Control.

Dependency Injection

When creating a class or module, it is good practice to reduce concrete dependencies when possible (Dependency Inversion Principle) . Concrete means having a hard dependency on another piece of code rather than a dependency on an abstraction.

This can be illustrated by defining a class. For example, a BillingForm may depend on a PaymentProcessor:

class BillingForm {
  constructor() {
    this.processor = new PaymentProcessor();
  }
  processForm(...) {
    this.processor.process(...);
  }
}

Contrast above with the following example where the dependency is added as an argument when constructing a BillingForm instance.

class BillingForm {
  constructor(paymentProcessor) {
    this.processor = paymentProcessor;
  }
  processForm(...) {
    this.processor.process(...);
  }
}
const paymentProcessor = new PaymentProcessor();
const billingForm = new BillingForm(paymentProcessor);

This is an example of IoC because the control of when a dependency is added is controlled by when the BillingForm is instantiated rather than immediately during the BillingForm instantiation.

React Lifecycle Methods

The Javascript frontend framework React.js has component lifecycle methods for components. Examples like componentWillMount, componentDidMount, and componentWillUnmount are defined in a component. These methods can be overridden by a component. The methods are then called at the appropriate time by the React.js framework.

Other examples includes: Command Line Interface, Javascript callbacks, Route Handlers, Object oriented class frameworks, and User Interfaces

Inversion of Control

Inversion of Control (IoC) is usually foundin programming, but it is a general concept. The concept relates to a program’s flow of control.

A program’s flow of control can be thought of as the direction a program executes. The simplest illustration of this is top-to-bottom line-by-line execution of a program.

console.log(1); 
console.log(2); 
console.log(3);

The numbers 1, 2, 3 will be logged into the console in this order. The written program has control of what and when the numbers are shown.

Contrast the above example with:

document.querySelector('.button-1')
.addEventListener('click', function(e) {
  console.log(1);
});
document.querySelector('.button-2')
.addEventListener('click', function(e) {
  console.log(2);
});

This code add event listeners to 2 buttons button-1 and button-2. The program describes what will happen (logging a number), but it has left when to the browser which in turn leaves it to the user of the browser. It is said that the control has been inverted away from the application/program (the code which defines the number logging) to the framework (the browser)

The word “framework” is an abstract and necessary concept when dealing with IoC since it would decide when certain methods shall be called.

To read more, check out Examples of Inversion of Control

Railscast – 016-Virtual-Attributes

The GitHub Repo
The Heroku app

I found this episode useful. It showed me that a model’s attribute does not have to be directly on one of the table’s columns. Not only did I learn about virtual attributes, but I also improved on associations, validations, and callbacks.

The virtual attributes were easy enough to understand. You create a setter and getter method named with the desired virtual attribute name. In the episode’s case it was price_in_cents sort of aliased to price_in_dollars. Within the method you could change the value of the virtual attribute to match whatever is in the database.

def price_in_dollars
  price_in_cents.to_d / 100 if price_in_cents
end

def price_in_dollars=(dollars)
  self.price_in_cents = dollars.to_d * 100 if dollars.present?
end 

Strftime

This is the first time I used the :strftime method, but it is not too dissimilar to how I have formatted dates within the terminal.

Rails 3 to Rails 4

One thing to note, these videos date back sometime before the current Ruby on Rails 4.0 release, thus I must convert some of the techniques shown in the videos into whatever they translate to in the new version of the framework. An example of this is the use of attr_accessible. Attr_accessible has been incorporated in the the strong parameters update in Rails 4. So instead of

attr_accessible :name, :price_in_dollars, :released_at_text, :category_id, :new_category, :tag_names

You would do the following in the ProductsController

def product_params
  params.require(:product).permit(:name, :price_in_dollars, :released_at_text, :category_id, :new_category, :tag_names)
end

Associations

I knew I was a little weak with associations, so when I saw that this project had categories, products, tags, and taggings, I decided to make everything from scratch. I followed along with the schema to create the migrations needed. When creating a has_many and belongs_to relationship you always put the parent id onto the child’s table. Example:

class Product < ActiveRecord::Base
  belongs_to :category
end

class Category < ActiveRecord::Base
  has_many :products
end

The schema would look like this:

 create_table "categories", :force => true do |t|
    t.string   "name"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  create_table "products", :force => true do |t|
    t.string   "name"
    t.integer  "category_id"
    t.datetime "created_at",     :null => false
    t.datetime "updated_at",     :null => false
  end

This relationship is similar to the taggings, tags, and products relationship. The taggings has the foreign key for both the tags and products. The difference is that products has_many tags through the taggings model.

Validations

I liked how Ryan Bates created his own custom validation method with check_released_at_text The validation first check if the released_at_text instance variable is present and the time is nil. If it is, then add to the errors object with a custom error message. If there was an ArgumentError, then again the errors object is appended with the custom error message. Creating a custom validation adds more control than if some of the more generic validation methods like presence or length.

Callbacks

The callbacks created this episode used before_save. The reasoning for this is to actually save the instance variable’s values to the database in the correctly formatted form. In the create_category callback it actually creates a new category record.

  def create_category
    self.category = Category.create!(name: new_category) if new_category.present?
  end

Pluck

The first time I’ve seen the pluck method used. I looked it up and found that tags.pluck(:name) is a shortcut for tags.map(&:name). The goal is to get only a certain attribute from the model.

Those where the noteworthy parts of the episode.