Thursday, December 22, 2011

Ruby Require vs Load

The load and require methods are use to include additional source files, these both methods you need to be used only if library you are loading is defined in a separate file.

These both methods defined under 'Kernel' module of ruby.

The require method allows you to load a library and prevents it from being loaded more than once. The require method will return ‘false’ if you try to load the same library after the first time.
So it keeps track of whether that library was already loaded or not. You also don’t need to specify the “.rb” extension of the library file name.

Here is the code from 'boot.rb'
require 'rubygems'

# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)

require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])

The load method is almost same like require method but it doesn’t keep track of whether specified library has been loaded or not. It should be used only if each time we want to load specific library and module changes done frequently. Here we need to specify the file extension.
load(File.dirname(__FILE__) + "/schema.rb")

Wednesday, December 7, 2011

Rails Counter Cache

Counter cache is a mechanism to cache the counts of associated model. The counter cache works by simply updating a parent model's count of related objects after each save or destroy operation on the child model. It increase the counts when associated object is created and decrease the counts when associated object is destroyed.

Why counter cache?
Many times we need the count's of child objects and we use through association to display counts on view in this case multiple SQL queries are raised just to get counts.
One of the traditional example is to display comment counts with every user.

class User < ActiveRecord::Base
  has_many :comments

class Comment < ActiveRecord::Base
  belongs_to :user

Now get user records with every user comment counts.

To display this counts what rails did.

To solve this issue we can go for active record counter cache.

How to implement counter cache?
We can implement counter cache in three steps

1) Create migration to add column in user table.
class AddCounterCacheToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :comments_count, :integer, :default => 0

  def self.down
    remove_column :users, :comments_count

2) Update existing record of user for comment counts
class AddCounterCacheToUsers < ActiveRecord::Migration
   def self.up
     add_column :users:comments_count:integer:default => 0
    User.find_each do |user|
      user.update_attribute(:comments_count, user.comments.length)

  def self.down
    remove_column :users:comments_count

After run the migration.
3) Apply counter cache on comment model.
class Comment < ActiveRecord::Base
  belongs_to :user , :counter_cache => true

and replace the code of user index view
  <%=h user.comments.length %>
  <%=h user.comments_count %>

Now we can get user comments count from same table with no extra query.

Monday, December 5, 2011

Rails Include vs Joins

Include & Join both are similar in the way, as because both are use to find the associated table value with single query. This is really very confusing what should we use :include or :joins. There is very nice article by railscasts also we can check the find method of active record.

I have conclude few point which make easier to take decision.

- It implies eager-loading on associations.
- It fetch all the class record or object attributes and keep it into the memory.
- It fetch all the associated object attributes with select option.
- It will be useful if want to use associated object attribute on view.
- By default it will do 'LEFT OUTER JOIN', which shows all the record from table.

As :include will do eager-loading, when try to fetch the user record then it will not raise another query.

- It actually do an 'INNER JOIN' which filters the rows that don't have association.
- It is for joining association names in different ways and joins the relevant tables.
- Every time it make a separate query to fetch the associated object attribute values.

As :joins is not doing eager-loading, when try to fetch the user record from comment it will raise another sql query.