Wednesday, July 11, 2012

Ruby : Rails : Mixins and Refactoring

I really love coding and to try out new things whenever possible. Though it's not always possible to do what I want but, one should fully utilize the opportunity when it presents itself.

Refactoring, it's one of the best things you can do for your code. After refactoring code becomes more readable, more secure and if everything work out good then refactoring also results in better performance.

And I got the opportunity I have been looking for, the Job was "To do refactoring" for one of the projects I've been working on.

Considering the project is for stores, there were 2 models rewards and promotions for store. The only difference between two was rewards do have points and not for promotions.

In reward.rb
class Reward < ActiveRecord::Base
  belongs_to :store

  validates_presence_of :store_id
  validates_presence_of :points
  validates_presence_of :description
  
  validates_numericality_of :points, :greater_than => 0
  
  validates :valid_from, :date => {}
  validates :valid_to, :date => { :after_or_equal_to => :valid_from }, :allow_blank => true

  scope :first_scope, lambda{ # some code }
  scope :second_scope, lambda { # some code }
  scope :third_scope, lambda { # some code }
end
In promotion.rb
class Promotion < ActiveRecord::Base
  belongs_to :store
  
  validates_presence_of :store_id
  validates_presence_of :description
  
  validates :valid_from, :date => {}
  validates :valid_to, :date => { :after_or_equal_to => :valid_from }, :allow_blank => true
  
  scope :first_scope,  lambda{ # some code }
  scope :second_scope, lambda { # some code }
end
Except that every thing from validations to associations were same.
Got irritated for a while, but then was happy that I was going to change the code.

So I added a module in lib as rewards_promotions.rb and added following code to it.
module RewardPromotion
  def self.included(base)
#    base.extend(ClassMethods)
    base.class_eval do
      belongs_to :store

      validates_presence_of :store_id
      validates_presence_of :description

      scope :first_scope, lambda{ # some code }
      scope :second_scope, lambda { # some code }
    end
  end
end
Now I just removed the similar code from respective models(reward.rb and promotion.rb) and just added following line
  include RewardPromotion
Thats it. My work was completed and I just restarted the server and everything worked as before. Just that the code was at one place and I dont have to repeat the same code for both models.
This was done for other models too and the project is now really great.

For refactoring I also avoided using if !true conditions to unless true.

Also the major calculations were called directly in controller from model. Which was converted to private method and then called from other method.
Need to understand the important functionality needs to go in private methods and be called from other method rather that directly making it available for controllers.
Refactoring was fun for me to get the things out of controllers and shifting to model with a great security and performance.

2 comments:

  1. Refactoring is a challenge.. one should enjoy taking it....!

    ReplyDelete
  2. truly said Manish.. Refactoring makes it possible to tweak the performance of whole application and try out things differently, Because while refactoring it's not just about writing code it's about writing correct code.. :)

    Thanks Supriya, for such a nice article..

    ReplyDelete