codedecoder

breaking into the unknown…


Leave a comment

copy object in ruby

When ever, you pass any object to any other method for manipulation, you should pass its copy rather then the original object to prevent any risk on the original object. See the below example.

we have below classes in bank_account.rb

class BankAccount
  attr_accessor :name, :balance
  def initialize(name,balance)
    @name = name
    @balance = balance
  end
end

class Invoice
  def print_account_holder_name(account_holder)
    puts account_holder.name.upcase
    account_holder.balance = 1000000
  end
end

BankAccount is the class which hold detail of accounts. Invoice class, generate the account report. Let us demonstrate the involved risk on console

1.9.3-p194 :014 > load “/home/arun/Documents/bank_account.rb” # give path of your bank_account.rb
1.9.3-p194 :016 > a = BankAccount.new(“arun”, 10000)
=> #<BankAccount:0xc9553d8 @name=”arun”, @balance=10000>
1.9.3-p194 :017 > Invoice.new.print_account_holder_name(a)
ARUN
1.9.3-p194 :019 > a.balance
=> 1000000

So you can see that, when print_account_holder_name method of invoice class is passed object of BankAccount class, it accidently or intentionally(in our case), increased the balance from 10000  to 10000000 . This can be avoided by passing the copy of object rather then the original object.

With the above background, we now understand the need of creating copy of object before passing to any other method or doing any manipulation over it. Let us see how we can do that i,e copy a object.

In ruby, everything is a object, even the data types. consciously or unconsciously, you have many a time created copy of these objects with assignment operator while programming.

try this in console

1.9.3-p194 :020 > a = 1
=> 1
1.9.3-p194 :023 > b = a
=> 1
1.9.3-p194 :024 > b += 1
=> 2
1.9.3-p194 :025 > a
=> 1
1.9.3-p194 :026 > b
=> 2

You can see that, you created b as a copy of a, when you add 1 to b, a do not changed i,e the manipulation occurred only on the copy b . But this way of creating copy work only for plain data type integer, string , text etc.

See again the above with a array value.

1.9.3-p194 :027 > a = [1,2]
=> [1, 2]
1.9.3-p194 :028 > b = a
=> [1, 2]
1.9.3-p194 :029 > b << 3
=> [1, 2, 3]
1.9.3-p194 :030 > a
=> [1, 2, 3]

So you can see that, creating copy with assignment operator = not worked and array assigned to a also get changed when the copy b is modified. This is because the Array object is not a primary data type. The assignment operator doesn’t make a copy of the value, it simply copies the reference to the Array object. The a and b variables are now references to the same Array object, any changes in either variable will be seen in the other.

Here dup and clone come to our rescue

1.9.3-p194 :031 > a = [1,2]
=> [1, 2]
1.9.3-p194 :032 > b = a.dup # a.clone also work
=> [1, 2]
1.9.3-p194 :033 > b << 3
=> [1, 2, 3]
1.9.3-p194 :034 > a
=> [1, 2]

So now you can see that with dup or clone, the changes on the copy not alter the original object a . Good… let us check the real scenario we have created in our  bank_account.rb.

1.9.3-p194 :039 > load “/home/arun/Documents/bank_account.rb”
=> true
1.9.3-p194 :040 > a = BankAccount.new(“arun”, 10000)
=> #<BankAccount:0xc94549c @name=”arun”, @balance=10000>
1.9.3-p194 :041 > b = a.clone
=> #<BankAccount:0xc936ce4 @name=”arun”, @balance=10000>
1.9.3-p194 :042 > c = a.dup
=> #<BankAccount:0xc929fa8 @name=”arun”, @balance=10000>
1.9.3-p194 :043 > Invoice.new.print_account_holder_name(b)
ARUN
1.9.3-p194 :044 > Invoice.new.print_account_holder_name(c)
ARUN
1.9.3-p194 :046 > a.balance
=> 10000

O.K, so this time we pass the copy b(created with dup) and copy c (created with clone) to the print_account_holder_name method of invoice class, and you can see that the balance of the original object a is secure .

Great…we will now onward create a copy of sensitive object before handing over it to any other interface for manipulation. But what is this … both dup and clone seems to doing the same thing : – copying the object . Yaa… superficially they are same, but do exhibit different behaviour. the difference can be stated in a single line as below.

clone maintain internal characteristic of copied object but dup do not .

Let us see the difference in the console.

=> dup do not maintain the frozen state of the object

1.9.3-p194 :011 > a = BankAccount.new(“arun”, 10000)
=> #<BankAccount:0x9997470 @name=”arun”, @balance=10000>
1.9.3-p194 :012 > a.freeze
=> #<BankAccount:0x9997470 @name=”arun”, @balance=10000>
1.9.3-p194 :013 > a.frozen?
=> true
1.9.3-p194 :014 > b = a.dup
=> #<BankAccount:0x99a1254 @name=”arun”, @balance=10000>
1.9.3-p194 :015 > b.frozen?
=> false
1.9.3-p194 :016 > c = a.clone
=> #<BankAccount:0x99a5cf0 @name=”arun”, @balance=10000>
1.9.3-p194 :017 > c.frozen?
=> true

So, you can see that, object a is frozen, but when it id copied with dup it become unfrozen, but remain same when copied with clone.

 

=> dup do not copy the singleton method of the object .

1.9.3-p194 :018 > a = BankAccount.new(“arun”, 10000)
=> #<BankAccount:0x99b1e38 @name=”arun”, @balance=10000>
1.9.3-p194 :019 > def a.iam_singleton
1.9.3-p194 :020?>   end

1.9.3-p194 :021 > a.methods
=> [:iam_singleton, :name, :name=, :balance, :balance=,:clone, :dup, :initialize_dup, :initialize_clone...]

1.9.3-p194 :023 > b = a.dup
=> #<BankAccount:0x99c3c3c @name=”arun”, @balance=10000>
1.9.3-p194 :024 > b.methods
=> [:name, :name=, :balance, :balance=,:clone, :dup, :initialize_dup, :initialize_clone...]

1.9.3-p194 :025 > c = a.clone
=> #<BankAccount:0x99d2110 @name=”arun”, @balance=10000>
1.9.3-p194 :026 > c.methods
=> [:iam_singleton, :name, :name=, :balance, :balance=,:clone, :dup, :initialize_dup, :initialize_clone...]

so we have added iam_singleton method to the object a . It is available to the copy c created with clone but not available to copy b created with dup.

NOTE : You can’t make copy of all the object. for example fixnum can’t be copied

 1.9.3-p194 :033 > 1.dup
TypeError: can’t dup Fixnum
1.9.3-p194 :033 > 1.clone
TypeError: can’t clone Fixnum

 

NOTE : you can customize the dup and clone method by redefining initialize_dup and initialize_clone method in your class, so overriding the original behaviour. Both initialize_dup and initialize_clone call initialize_copy method internally

O.K..so we now know the difference between dup and clone. But which one we should use. Well it is upto you. Personally, I prefer dup, as I know that Iam having only the copy of the object, so I can mess with it. I do not want any limitation on the copy I’ am having . Limitation is always a pain..isn’t it…go with dup. :)

 

Reference:

http://ruby-doc.org/core-2.1.2/Object.html#method-i-dup

http://ruby-doc.org/core-2.1.2/Object.html#method-i-clone

http://m.onkey.org/ruby-i-don-t-like-3-object-freeze

 


Leave a comment

eager loading in rails

recently I got a interview call from a reputed company and come to know that, I have not so good understanding of data loading in rails. So, I tried to dig deeper into data loading. To start with – data can be loaded in two ways : lazy loading and eager loading. The first one refer to loading associated data when need arises and second one refer to loading the associated data , at the time of retrieving the parent object itself. say you have below association

class Physician < ActiveRecord::Base
  has_many :appointments
  has_many :patients, :through => :appointments
  attr_accessible :name, :specialization, :mobile_no
end
 
class Appointment < ActiveRecord::Base
  belongs_to :physician
  belongs_to :patient
  attr_accessible :reason, :physician_id, :patient_id
end
 
class Patient < ActiveRecord::Base
  has_many :appointments
  has_many :physicians, :through => :appointments
  attr_accessible :name, :mobile_no
end

The corresponding tables for them will look as below :

class CreatePhysicians < ActiveRecord::Migration
  def change
    create_table :physicians do |t|
      t.string :name
      t.string :specialization
      t.integer :mobile_no
      t.timestamps
    end
  end
end

class CreateAppointments < ActiveRecord::Migration
  def change
    create_table :appointments do |t|
      t.string :reason
      t.references :physician
      t.references :patient
      t.timestamps
    end
  end
end

class CreatePatients < ActiveRecord::Migration
  def change
    create_table :patients do |t|
      t.string :name
      t.integer :mobile_no
      t.timestamps
    end
  end
end

Let us create some seed data to experiment with. Add below in your seeds.rb file

Physician.create(:name => "Arun", :specialization => "ENT", :mobile_no => "9569806453")
Physician.create(:name => "Anand", :specialization => "MS", :mobile_no => "9569807853")

Patient.create(:name => "Raman", :mobile_no => "9569807851")
Patient.create(:name => "Kapil", :mobile_no => "9569807852")
Patient.create(:name => "Gita", :mobile_no => "9569807853")
Patient.create(:name => "Santosh", :mobile_no => "9569807854")

Appointment.create(:reason => "Ear pain", :physician_id  => 1, :patient_id => 2)
Appointment.create(:reason => "Teeth pain", :physician_id  => 1, :patient_id => 3)
Appointment.create(:reason => "Teeth pain", :physician_id  => 1, :patient_id => 4)
Appointment.create(:reason => "Surgery", :physician_id  => 2, :patient_id => 4)
Appointment.create(:reason => "Surgery", :physician_id  => 2, :patient_id => 1)

run rake db:seed to populate the above data.

Now we have the association ready along with some dummy data.But before proceeding further, try to understand, why we need eager loading. Say the hospital need to generate a report for the months, indicating the number of patients handled by a individual doctor. You may do something like this.

1.9.3-p194 :052 > @doctors = Physician.all
Physician Load (0.2ms)  SELECT `physicians`.* FROM `physicians`
=> [#<Physician id: 1, name: "Arun", specialization: "ENT", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Physician id: 2, name: "Anand", specialization: "MS", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :059 > @doctors.each do |doctor|
1.9.3-p194 :060 >     doctor.patients.each do |patient|
1.9.3-p194 :061 >       puts patient.name
1.9.3-p194 :062?>     end
1.9.3-p194 :063?>   end
Patient Load (0.2ms)  SELECT `patients`.* FROM `patients` INNER JOIN `appointments` ON `patients`.`id` = `appointments`.`patient_id` WHERE `appointments`.`physician_id` = 1
Kapil
Gita
Santosh
Patient Load (0.3ms)  SELECT `patients`.* FROM `patients` INNER JOIN `appointments` ON `patients`.`id` = `appointments`.`patient_id` WHERE `appointments`.`physician_id` = 2
Raman
Santosh

So, you can see that for 2 doctors in database, 3 queries hitting the database. the first query was to retrieve all the doctors and 2 queries to retrieve the details of there patients. So it leads to n+ 1 queries hitting database. Imagine the load on database, if there is thousands of doctors. This can be avoided by eager loading

Now we are ready to get into the detail of eager loading.The first thing to remember is that, you can do eager loading in any of the following ways

=> includes
=> preload
=> eager_load

O.K so we have too many ways to do eager loading. Let us see how they differ by trying out them on console .

1.9.3-p194 :039 > @doctors = Physician.includes(:patients)
Physician Load (0.3ms)  SELECT `physicians`.* FROM `physicians`
Appointment Load (0.2ms)  SELECT `appointments`.* FROM `appointments` WHERE `appointments`.`physician_id` IN (1, 2)
Patient Load (0.3ms)  SELECT `patients`.* FROM `patients` WHERE `patients`.`id` IN (2, 3, 4, 1)
=> [#<Physician id: 1, name: "Arun", specialization: "ENT", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Physician id: 2, name: "Anand", specialization: "MS", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :040 > @doctors.first.patients
=> [#<Patient id: 2, name: "Kapil", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 3, name: "Gita", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 4, name: "Santosh", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :041 > @doctors.first.appointments
=> [#<Appointment id: 1, reason: "Ear pain", physician_id: 1, patient_id: 2, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Appointment id: 2, reason: "Teeth pain", physician_id: 1, patient_id: 3, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Appointment id: 3, reason: "Teeth pain", physician_id: 1, patient_id: 4, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]

 

1.9.3-p194 :043 > @doctors = Physician.preload(:patients)
Physician Load (0.1ms)  SELECT `physicians`.* FROM `physicians`
Appointment Load (0.1ms)  SELECT `appointments`.* FROM `appointments` WHERE `appointments`.`physician_id` IN (1, 2)
Patient Load (0.1ms)  SELECT `patients`.* FROM `patients` WHERE `patients`.`id` IN (2, 3, 4, 1)
=> [#<Physician id: 1, name: "Arun", specialization: "ENT", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Physician id: 2, name: "Anand", specialization: "MS", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :044 > @doctors.first.patients
=> [#<Patient id: 2, name: "Kapil", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 3, name: "Gita", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 4, name: "Santosh", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :045 > @doctors.first.appointments
=> [#<Appointment id: 1, reason: "Ear pain", physician_id: 1, patient_id: 2, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Appointment id: 2, reason: "Teeth pain", physician_id: 1, patient_id: 3, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Appointment id: 3, reason: "Teeth pain", physician_id: 1, patient_id: 4, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]

 

1.9.3-p194 :046 > @doctors = Physician.eager_load(:patients)
SQL (0.4ms)  SELECT `physicians`.`id` AS t0_r0, `physicians`.`name` AS t0_r1, `physicians`.`specialization` AS t0_r2, `physicians`.`mobile_no` AS t0_r3, `physicians`.`created_at` AS t0_r4, `physicians`.`updated_at` AS t0_r5, `patients`.`id` AS t1_r0, `patients`.`name` AS t1_r1, `patients`.`mobile_no` AS t1_r2, `patients`.`created_at` AS t1_r3, `patients`.`updated_at` AS t1_r4 FROM `physicians` LEFT OUTER JOIN `appointments` ON `appointments`.`physician_id` = `physicians`.`id` LEFT OUTER JOIN `patients` ON `patients`.`id` = `appointments`.`patient_id`
=> [#<Physician id: 1, name: "Arun", specialization: "ENT", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Physician id: 2, name: "Anand", specialization: "MS", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :047 > @doctors.first.patients
=> [#<Patient id: 2, name: "Kapil", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 3, name: "Gita", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 4, name: "Santosh", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :048 > @doctors.first.appointments
Appointment Load (0.3ms)  SELECT `appointments`.* FROM `appointments` WHERE `appointments`.`physician_id` = 1
=> [#<Appointment id: 1, reason: "Ear pain", physician_id: 1, patient_id: 2, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Appointment id: 2, reason: "Teeth pain", physician_id: 1, patient_id: 3, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Appointment id: 3, reason: "Teeth pain", physician_id: 1, patient_id: 4, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]

strange, appointment is not loading the through relation appointments and firing a separate query for it .let us try again by including it explicitly.

1.9.3-p194 :064 > @doctors = Physician.eager_load(:patients,:appointments)
SQL (0.4ms)  SELECT `physicians`.`id` AS t0_r0, `physicians`.`name` AS t0_r1, `physicians`.`specialization` AS t0_r2, `physicians`.`mobile_no` AS t0_r3, `physicians`.`created_at` AS t0_r4, `physicians`.`updated_at` AS t0_r5, `patients`.`id` AS t1_r0, `patients`.`name` AS t1_r1, `patients`.`mobile_no` AS t1_r2, `patients`.`created_at` AS t1_r3, `patients`.`updated_at` AS t1_r4, `appointments_physicians`.`id` AS t2_r0, `appointments_physicians`.`reason` AS t2_r1, `appointments_physicians`.`physician_id` AS t2_r2, `appointments_physicians`.`patient_id` AS t2_r3, `appointments_physicians`.`created_at` AS t2_r4, `appointments_physicians`.`updated_at` AS t2_r5 FROM `physicians` LEFT OUTER JOIN `appointments` ON `appointments`.`physician_id` = `physicians`.`id` LEFT OUTER JOIN `patients` ON `patients`.`id` = `appointments`.`patient_id` LEFT OUTER JOIN `appointments` `appointments_physicians` ON `appointments_physicians`.`physician_id` = `physicians`.`id`
=> [#<Physician id: 1, name: "Arun", specialization: "ENT", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Physician id: 2, name: "Anand", specialization: "MS", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :065 > @doctors.first.patients
=> [#<Patient id: 2, name: "Kapil", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 3, name: "Gita", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 4, name: "Santosh", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :066 > @doctors.first.appointments
=> [#<Appointment id: 1, reason: "Ear pain", physician_id: 1, patient_id: 2, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Appointment id: 2, reason: "Teeth pain", physician_id: 1, patient_id: 3, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Appointment id: 3, reason: "Teeth pain", physician_id: 1, patient_id: 4, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]

you can see that, this time the through association appointment also get eager loaded and no separate query fired for it.

O.K….so let us stop here and analyse the above result.

=> includes and preload made 3 queries to database . eager_load made single query to database
=> the 3 queries made by includes and preload is small queries targeted to the three table physicians, appointments and patients. the single query by eager_load involve join of all the three table
=> the query executed by includes and preload is exactly same, but eager_load query differ from both
=> eager_load do not load the through association implicitly, but you have to specify it explicitly.
=> overall time taken by includes is 0.8ms,preload is 0.3ms and eager_load is o.4ms

So, it is clear that executing a set of small queries through preload is faster than, executing a big join of these queries. Also join suffer from cartesian product overload problem as join produce a number of duplicate record which though not affect the database but hit rails on its back as it have to deal with larger number of small and short lived object.

Here rails show its smartness through includes. Actually internally rails eager load data through preload(i,e set of small queries) or eager_load(i,e through join). include just delegate the eager load to preload or eager_load depending on the nature of query you are making. In simple word, If you are not sure which is more efficient for you : preload or eager_load, just use include and it will smartly decide which one is better and delegate the job to that.

Let us see it in action on console.

1.9.3-p194 :002 > @doctors = Physician.includes(:patients).where(“patients.mobile_no != ?”, “765778989”)
SQL (0.4ms)  SELECT `physicians`.`id` AS t0_r0, `physicians`.`name` AS t0_r1, `physicians`.`specialization` AS t0_r2, `physicians`.`mobile_no` AS t0_r3, `physicians`.`created_at` AS t0_r4, `physicians`.`updated_at` AS t0_r5, `patients`.`id` AS t1_r0, `patients`.`name` AS t1_r1, `patients`.`mobile_no` AS t1_r2, `patients`.`created_at` AS t1_r3, `patients`.`updated_at` AS t1_r4 FROM `physicians` LEFT OUTER JOIN `appointments` ON `appointments`.`physician_id` = `physicians`.`id` LEFT OUTER JOIN `patients` ON `patients`.`id` = `appointments`.`patient_id` WHERE (patients.mobile_no != ‘765778989’)
=> [#<Physician id: 1, name: "Arun", specialization: "ENT", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Physician id: 2, name: "Anand", specialization: "MS", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]

So, you can see that, this time includes fire a single query through join. Here rails saw that, patient to be retrieved has some condition imposed on it, so delegated the job to eager_load internally rather then preload. Note that you can’t eager load conditional data using preload. try the above query through preload.

1.9.3-p194 :003 > @doctors = Physician.preload(:patients).where(“patients.mobile_no != ?”, “765778989”)
Physician Load (0.3ms)  SELECT `physicians`.* FROM `physicians` WHERE (patients.mobile_no != ‘765778989’)
Mysql2::Error: Unknown column ‘patients.mobile_no’ in ‘where clause': SELECT `physicians`.* FROM `physicians`  WHERE (patients.mobile_no != ‘765778989’)
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column ‘patients.mobile_no’ in ‘where clause': SELECT `physicians`.* FROM `physicians`  WHERE (patients.mobile_no != ‘765778989’)

So we get the error as expected.

Now let us make some conclusion at this point
=> use includes if you want rails to decide, to load data in single join query or small set of queries
=> use eager_load if you want to make single query to db without leaving the decision to includes
=> use preload when you want to load data with set of queries

use of preload do not look convincing…right? . let us see a case, where preload can only fit the need. Say you want the physician whose patient is Raman, but at the same time you want to eager load all the patient of that physician.

The query to find doctor whose patient is raman is as below.
1.9.3-p194 :019 > @doctors=Physician.joins(:patients).where(“patients.name = ?”, “Raman”)
Physician Load (0.1ms) SELECT `physicians`.* FROM `physicians` INNER JOIN `appointments` ON `appointments`.`physician_id` = `physicians`.`id` INNER JOIN `patients` ON `patients`.`id` = `appointments`.`patient_id` WHERE (patients.name = ‘Raman’)
=> [#]

let us chain includes to the above query to eager load the patients detail

1.9.3-p194 :017 > @doctors=Physician.joins(:patients).where(“patients.name = ?”, “Raman”).includes(:patients)
SQL (0.4ms) SELECT `physicians`.`id` AS t0_r0, `physicians`.`name` AS t0_r1, `physicians`.`specialization` AS t0_r2, `physicians`.`mobile_no` AS t0_r3, `physicians`.`created_at` AS t0_r4, `physicians`.`updated_at` AS t0_r5, `patients`.`id` AS t1_r0, `patients`.`name` AS t1_r1, `patients`.`mobile_no` AS t1_r2, `patients`.`created_at` AS t1_r3, `patients`.`updated_at` AS t1_r4 FROM `physicians` INNER JOIN `appointments` ON `appointments`.`physician_id` = `physicians`.`id` INNER JOIN `patients` ON `patients`.`id` = `appointments`.`patient_id` WHERE (patients.name = ‘Raman’)
 => [#<Physician id: 2, name: "Anand", specialization: "MS", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :018 > @doctors.first.patients
=> [#<Patient id: 1, name: "Raman", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]

So you can see that here, eager loading returning the patient Raman only as includes , seeing where clause in the query delgate the job to eager_load which create a single join with the given condition, returning only the single patient raman.

Now fire the same query, using preload.

1.9.3-p194 :015 > @doctors=Physician.joins(:patients).where(“patients.name = ?”, “Raman”).preload(:patients)
Physician Load (0.2ms)  SELECT `physicians`.* FROM `physicians` INNER JOIN `appointments` ON `appointments`.`physician_id` = `physicians`.`id` INNER JOIN `patients` ON `patients`.`id` = `appointments`.`patient_id` WHERE (patients.name = ‘Raman’)
Appointment Load (0.1ms)  SELECT `appointments`.* FROM `appointments` WHERE `appointments`.`physician_id` IN (2)
Patient Load (0.1ms)  SELECT `patients`.* FROM `patients` WHERE `patients`.`id` IN (4, 1)
=> [#<Physician id: 2, name: "Anand", specialization: "MS", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]
1.9.3-p194 :016 > @doctors.first.patients
=> [#<Patient id: 4, name: "Santosh", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">, #<Patient id: 1, name: "Raman", mobile_no: 2147483647, created_at: "2014-07-21 11:51:18", updated_at: "2014-07-21 11:51:18">]

This time you got all the patients of the physician Anand.

So, we are done with our research on data loading in rails.

But wait….Rails still evolving, and it keep changing with each release. The includes has also changed in rails4. Now rails has stopped being super smart. thus it will not automatically delegate the job to eager_load on seing a where clause in the query. instead, you need to pass the reference of the table whose attributes used in the where clause.

Example :

@doctors = Physician.includes(:patients).where(“patients.mobile_no != ?”, “765778989”) # will throw error

@doctors = Physician.includes(:patients).where(“patients.mobile_no != ?”, “765778989”).references(:patients) # will work

 

Reference :
http://guides.rubyonrails.org/active_record_querying.html
http://stackoverflow.com/questions/1208636/rails-include-vs-joins


Leave a comment

inactivity warning and logout timer

Almost all the secured Application support session time out due to inactivity after specific period of time say 15 minute or 30 minute. It is good to warn the user of logout due to inactivity. Say if your application support session expire on 30 minutes of inactivity. warn user at 25 minutes. If he do not click on the warning for next 5 minute but say after 6 minute, log him out.

You should note that, you have to handle the session expiry at your application level. I am from ruby on rails background and handle this with devise gem. Devise internally clear session and cookies, if the user is inactive for 30 minute. So if user come after 30 minutes and try to reload or submit the page he is taken back to the login page.

Here, we will warn the user at 25 minutes and log him out after 30 minutes.

The logic should be :

=> You need to track user doing something on your site or not. If not keep increasing the idle time.

=> If idle time reach 25 minute give him warning popup ( I used bootstrap modal for the popup)

      NOTE : don’t use alert . it will stop your timer

=> Once popup is shown, keep counting the sub-time for the logout

=> If user come after sub-time log him out

      NOTE : In my case, as I have told above session expiry is managed by devise, reloading the page is sufficient to take user back to the login page.

In case your application do not do that, clear session cookies etc using jquery (not covered in this post) and redirect him to login page.

=> whenever user show some activity : move mouse, press key or reload page, reset the timer i,e idle time to 0 value.

To create the timer we will use setInterval and clearInterval function of JavaScript . setInterval repeat the code within it after the specified time. The time is specified in milisecod i,e if you want to repeat the process after 1 seocnd, you should pass 1000 to it .

let us first create other required things.

=> create Alert PopUP.

As mentioned above alert will stop the execution of setInterval. so let us create our own popup. I have used bootstrap . The code is as below.

<div id="inactivity_warning" class="modal hide fade" data-backdrop="static" style="top:30%">
  <div class="modal-header">
    <button type="button" class="close inactivity_ok" data-dismiss="modal" aria-hidden="true">&times;</button>
  </div>
  <div class="modal-body">
    <div class="row-fluid">
      <div id="custom_alert_message" class="span12">
       You will be logged out in 5 minutes due to inactivity. Please save your credit 
       application if you have not already done so.
     </div>
   </div>
  <div class="modal-footer">
    <a href="javascript:void(0)" class="btn inactivity_ok" data-dismiss="modal" aria-hidden="true">O.K</a>
   </div>
  </div>
</div>

save these lines in you layout so that it is available through out the application.

=> set hidden flag to decide logout and timer

Below hidden field will decide whether to logout the user or not. we will change its value to inactive when time reach 30 minutes .Set the user_loged_in value to true when user is loged in, otherwise keep it false

<input id="user_activity" name="user_activity" type="hidden" value="active" />
<input id="user_loged_in" name="user_loged_in" type="hidden" value="true" />

=> jquery code for timer

    // reset main timer i,e idle time to 0 on mouse move, keypress or reload
    window.onload = reset_main_timer;
    document.onmousemove = reset_main_timer;
    document.onkeypress = reset_main_timer;
    
    // create main_timer and sub_timer variable with 0 value, we will assign them setInterval object
    var main_timer = 0;
    var sub_timer = 0;

    // this will ensure that timer will start only when user is loged in
    var user_loged_in = $("#user_loged_in").val()

   // within dilog_set_interval function we have created object of setInterval and assigned it to main_timer.
   // within this we have again created an object of setInterval and assigned it to sub_timer. for the main_timer
   // value is set to 15000000 i,e 25 minute.note that if subtimer repeat itself after 5 minute we set user_activity
   // flag to inactive
    function dialog_set_interval(){
        main_timer = setInterval(function(){
            if(user_loged_in == "true"){
                $("#inactivity_warning").modal("show");
                sub_timer = setInterval(function(){
                    $("#user_activity").val("inactive")
                },300000);
            }
        },1500000);
    }
   // maintimer is set to 0 by calling the clearInterval function. note that clearInterval function takes
   // setInterval object as argument, which it then set to 0
    function reset_main_timer(){
        clearInterval(main_timer);
        dialog_set_interval();
    }

    // logout user if user_activity flag set to inactive, when he click ok on popup. whenuser click O.K
    // on the warning the subtimer is reset to 0
    $(".inactivity_ok").click(function(){
        clearInterval(sub_timer);
        if($("#user_activity").val() == "inactive"){
            window.location = window.location // if your application not manage session expire 
                                              //automatically. clear cookies and session her
        }
    });

NOTE : value taken by setInterval is in milisecond i,e 1000 = 1 second. In the above code 25 minutes = 15000000 and 5 minute = 300000

 

Reference:

https://developer.mozilla.org/en/docs/Web/API/window.setInterval

https://developer.mozilla.org/en-US/docs/Web/API/window.clearInterval

http://codedecoder.wordpress.com/2013/02/08/rails-with-bootstrap-javascript-jquery-plugin/

 

 


1 Comment

difference between private protected public in ruby

private, protected and public control the visibility of methods in ruby class .By default methods in ruby are public except global and initialize method which are private by default. As far as variable are concerned they are private by default as variable can’t be seen by them self but through getter and setter method defined for a variable. you can define the getter and setter method yourself, which is not actually needed as it can be achieved by using :attr_accessor. the variables for which you have defined getter and setter methods behave as public. constants are effectively public , there is no way to define a constant that is inaccessible to outside use. we can say that public, private and protected apply only to methods

private, protected and public are not any keyword but actual method of object class that operate on any other class, dynamically altering the visibility of its methods . you can get the list of private, protected or public method of a class by using private_methods , protected_methods and public_methods on it.

private, protected and public take methods name as argument. If you do not pass argument all the method following them will have the same visibility until it is changed by applying the other. Let us illustrate it with examples in visibility_demo.rb files

# this global method defined outside class so private
def iam_global
  puts "Iam global"
end

class VisibilityDemo

  def initialize
    @message = "Iam the class demonstrating visibility in ruby"
  end
  # No visibility specifier given so public by default

  def pub_method
    puts "Iam public"
  end

  private
  # This method appears after the private' visibility specifier so private
  def pri_method
    puts "Iam private"
  end

  # This method is also private because the previous visibility not overridden
  # specifier has not been overridden
  def pri_method2
    puts "Iam private"
  end

  protected
  # This method appears after the protected visibility specifier so protected
  def pro_method
    puts "Iam protected"
  end

  public
  #this method overridden above protected specifier and become public
  def pub_method2
    puts "Iam public"
  end
end

The risk in above way of defining the visibility (visibility specifier without arguments) is that all following method will have same behaviour(try by changing the position of say private, keep it at top), which we not always want, so it is better to use them in argument form if the list of particular visibility is not very long. Let us redefine it in argument form and also add some other piece of code, needed to demo visibility behaviour.

def iam_global
  puts "Iam global"
end

class VisibilityDemo

  def initialize
    @message = "Iam the class demonstrating visibility in ruby"
  end

  def pub_method
    puts "#{self}"
    puts "Iam public"
  end

  def pri_method
    puts "Iam private"
  end

  def pri_method2
    puts "Iam private"
  end

  def pro_method
    puts "Iam protected"
  end

  def demo_explicit_object_calling_pro(obj)
    #call the protected method on explcit object
    obj.pro_method
  end

  def pub_method2
    puts "Iam public"
  end

  #specifying visibility specifier with argument
  private :pri_method, :pri_method2
  protected :pro_method
end

#class inheriting from VisibilityDemo class
class InheritVisibility < VisibilityDemo
  # the will call methods of parent class with self as explicit receiver
  def call_methods_with_self
    self.pub_method
    self.pro_method
    self.pri_method
  end

  # the will call methods of parent class without any receiver
  def call_methods_without_receiver
    pub_method
    pro_method
    pri_method
  end

  #overriding private method of parent class
  def pri_method2
   puts "I have overrided parent and become public"
  end

end

#class not inheriting from VisibilityDemo
class AnyClass
  def call_methods
    pub_method
    pro_method
    pri_method
  end  
end

Now let us list all the types of method on irb console
> load “/home/arun/Desktop/visibility_demo.rb” #load the visibility_demo.rb file
=> true
> @visbiility_demo = VisibilityDemo.new # create instance of VisibilityDemo class
=> #
> @visbiility_demo.public_methods # list the public methods
=> [:pub_method, :pub_method2,...]
> @visbiility_demo.protected_methods # list the protected methods
=> [:pro_method]
> @visbiility_demo.private_methods  # list the private methods
=> [:initialize, :pri_method, :pri_method2, :iam_global, ..] # see that initialize and iam_global listed under private

O.K, so we now know how to set the visibility of a method. Let us now see how the visibility specifier change the behaviour of methods in its own class and its inherited classes.

NOTE : before you proceed you must be clear on self and implicit and explicit receiver of a method . You should also know that, there is three way of calling any method : method_name , self.method_name, @object.method_name

1 => irrespective of its visibility any method can be called only in its class hierarchy

See the below output on irb :

> @any_class = AnyClass.new # create instance of any class
 => #<AnyClass:0x942b25c>
> @any_class.pub_method # call the pub method of VisibilityDemo class
NoMethodError: undefined method `pub_method’ for #<AnyClass:0x942b25c> #give error , can’t be called
> @any_class.pro_method # call the protected method of VisibilityDemo class
NoMethodError: undefined method `pro_method’ for #<AnyClass:0x942b25c> #give error , can’t be called
> @any_class.pri_method # call the private method of VisibilityDemo class
NoMethodError: undefined method `pri_method’ for #<AnyClass:0x942b25c> #give error , can’t be called
> @any_class.call_methods # call method of AnyClass calling VisibilityDemo class method implicitly
NoMethodError: undefined method `pub_method’ for #<AnyClass:0x942b25c>

2 => Public method can be called on any object in the class hierarchy as the explicit receiver, but protected and private can’t

See the below output on the irb console :

> self
=> main
> @visbility_demo = VisibilityDemo.new # creating object of  VisibilityDemo class
 => #<VisibilityDemo:0x970c214 @message=”Iam the class demonstrating visibility in ruby”>
> @visbility_demo.pub_method #call the public method
Iam public
> @visbility_demo.pro_method #call the protected method
NoMethodError: protected method `pro_method’ called for #<VisibilityDemo:0x970c214> # give error
> @visbility_demo.pri_method #call the private method
NoMethodError: private method `pri_method’ called for #<VisibilityDemo:0x970c214> # give error

NOTE : Here there is one exception for protected method, protected method can also be called on a object if its belongs to the same class as self.

In the above output , you are running the code from irb and so at this point of program self is main, but the object @visbility_demo belongs to VisibilityDemo class, since the class of self and the class of object is different, the protected method throw error. See the below output where protected method called on explicit object and worked fine.

> @visbiility_demo = VisibilityDemo.new # creating object of VisibilityDemo
 => #<VisibilityDemo:0x955e034 @message=”Iam the class demonstrating visibility in ruby”>
> obj = VisibilityDemo.new # creating another object of VisibilityDemo
 => #<VisibilityDemo:0x9531408 @message=”Iam the class demonstrating visibility in ruby”>
> @visbiility_demo.demo_explicit_object_calling_proc(obj) #for demo_explicit_object_calling_proc method self is VisibilityDemo and since object passed to it is also of same class, the protected method worked this time
Iam protected

3 => Public and Protected both can be called with self as explicit receiver but Private can’t

See the below output on the irb console

> @inherting_visibility = InheritVisibility.new # create instance of the inheriting class
 => #<InheritVisibility:0x96e068c @message=”Iam the class demonstrating visibility in ruby”>
> @inherting_visibility.call_methods_with_self # call the method calling parent class method with self
Iam public # public method called successfully with self
Iam protected # protected method called successfully with self
NoMethodError: private method `pri_method’ called for #<InheritVisibility:0x96e068c> # private method give error

4 => public protected and private all can be called implicitly i,e without any receiver

See the below output on irb console:

> @inherting_visibility = InheritVisibility.new
 => #<InheritVisibility:0x96e068c @message=”Iam the class demonstrating visibility in ruby”>
> @inherting_visibility.call_methods_without_receiver
Iam public
Iam protected
Iam private

5 => If a private method overridden in its subclass, the method exhibit visibility as defined in subclass

see the below output in irb console

> @visibility_demo = VisibilityDemo.new # create object of VisibilityDemo class
 => #<VisibilityDemo:0x9e49734 @message=”Iam the class demonstrating visibility in ruby”>
> @visibility_demo.pri_method2 # call the private method
NoMethodError: private method `pri_method2′ called for #<VisibilityDemo:0x9e49734> # error as expected
> @inherit_visibility = InheritVisibility.new # create object of subclass of VisibilityDemo class which override the method
 => #<InheritVisibility:0x9f01e4c @message=”Iam the class demonstrating visibility in ruby”>
> @inherit_visibility.pri_method2 # call the private method of parent again
I have overrided parent and become public # it worked this time as it is overridden in the subclass 

So, from the above points we can summarized the behaviour as below :

Private method can be called only implicitly (i,e without any receiver) . Protected method can be called with a explicit receiver but that should be self or if a object, the object must belong to same class as self . Public method can be called in any way in its class hierarchy .

So through above point ruby ensure that private method should never we called on a object and let ruby invoke it by its own. Remember that you can create instance of any class anywhere and if a highly secure method say which manipulate user balance, call it current_account_balance is not private, then any person can misuse it by creating the object of class and calling the method.

Here, ruby differ in private implementation in C and c++ . In C ++  “private” means “private to this class”, while in Ruby it means “private to this instance”. What this means, in C++ from code in class A, you can access any private method for any other object of type A. In Ruby, you can not: you can only access private methods for your instance of object, and not for any other object instance (of class A).

It should be also noted that, ruby prevent accidental misuse of private method, but not prevent it strictly. So if you want, you can invoke a private method on an object also with send, see the below output on console

> @visibility_demo = VisibilityDemo.new
 => #<VisibilityDemo:0x9e8c804 @message=”Iam the class demonstrating visibility in ruby”>
> @visibility_demo.pri_method # trying to call the private method on object
NoMethodError: private method `pri_method’ called for #<VisibilityDemo:0x9e8c804> #throw no method error
> @visibility_demo.send(:pri_method) # # trying to call the private method on object with send
Iam private #it worked

Since, private method can’t be called on its own object also, but there are some cases where we me need it, so there we can make the method protected. Let us take a simple example below in file say my_bank.rb

class BankRate

  def initialize(bank_name, rate)  
    @bank_name = bank_name
    @rate      = rate  
  end 

  def bank_name
     @bank_name
  end 

  def current_rate  
    @rate  
  end 

  def comparative_rate(bank)  
    if bank.current_rate > current_rate  
      "#{bank.bank_name} have higher rate then #{@bank_name}"  
    else  
      "#{bank.bank_name} have higher rate then #{@bank_name}"  
    end  
  end 

  private :current_rate  
end  

# call the comprative_rate method
@sbi = BankRate.new("sbi", 12)  # first object of BankRate class
@icici = BankRate.new("icici", 14)  # secone object of same BankRate class
puts  @sbi.comparative_rate(@icici) # calling comprative_rate method on first object and passing second as argument

So, we have a BankRate class dealing with bank rate. We want that, the current_rate should not be misused so we have made it private. This class also have a method which compare the rate of the bank with another bank . Try to load the my_bank.rb file on console

> load “/home/arun/Desktop/my_bank.rb” #load my_bank.rb file
NoMethodError: private method `current_rate’ called for #<BankRate:0x9f90d90 @bank_name=”icici”, @rate=14>

So you can see that, although the @sbi  and @icici bot are object of the same class, still they can’t invoke the private method. Now change the visibility of current_method to protected in above file i,e protected :current_rate and run it again.

> load “/home/arun/Desktop/visibility_demo.rb” #load my_bank.rb file again
icici have higher rate then sbi # it worked this time

So, this worked this time. This demonstrate when to use private and when to use protected.

Reference :

http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes

http://lylejohnson.name/blog/2003/12/09/private-methods-in-c-and-ruby/ # comparison with c, c++


Leave a comment

multiple project using sidekiq on same machine

In this post I have explained how to install , configure, start and stop sidekiq . You can start sidekiq from terminal with below command on your project root

$ bundle exec sidekiq -e staging -d -L log/sidekiq.log # -e option set the environment (staging in this case), -d option make the sidekiq to start as daemon i,e it will keep running even after you close the terminal, -L option set the log file path, you can get the list of all available option with -h as below

$ sidekiq -h
-c, –concurrency INT                           processor threads to use
-d, –daemon                                           Daemonize process
-e, –environment ENV                          Application environment
-g, –tag TAG                                            Process tag for procline
-i, –index INT                                         unique process index on this machine
-p, –profile                                              Profile all code run by Sidekiq
-q, –queue QUEUE[,WEIGHT]…       Queues to process with optional weights
-r, –require [PATH|DIR]                     Location of Rails application with workers or file to require
-t, –timeout NUM                                  Shutdown timeout
-v, –verbose                                            Print more verbose output
-C, –config PATH                                  path to YAML config file
-L, –logfile PATH                                 path to writable logfile
-P, –pidfile PATH                                 path to pidfile
-V, –version                                           Print version and exit
-h, –help                                                 Show help

O.K , so we know how to start sidekiq with all the possible option. But what happen if you start the sidekiq on two or more project on the same machine. In my case, My staging server host two projects, and all of them need sidekiq as background worker, so I moved to project folder and started sidekiq on both

ThirdPillar]# bundle exec sidekiq -e staging -d -L log/sidekiq.log
Barcelona]# bundle exec sidekiq -e staging -d -L log/sidekiq.log

Now I checked the running instance of sidekiq

ps -ef | grep sidekiq
root      3823     1  1 03:03 ?  00:00:38 sidekiq 2.12.0 ThirdPillar [0 of 25 busy]
root      4116     1  1 03:04 ?  00:00:35 sidekiq 2.12.0 Barcelona [0 of 25 busy]

So, I can see that, sidekiq have started on both the project and running on different port. But when I tried to load my application, all the pages which involve background processing start breaking. So the sidekiq not working . If I kill one sidekiq, the other start working. It is obvious that, the multiple sidekiq daemon conflicting with each other.

Now understand why is the conflict :

=> sidekiq work on redis as database server. basically it store the background processes on redis

=> One machine can have only single redis server, but redis can have multiple database on it

=> Unless you provide separate redis configuration for sidekiq, it will work with default i,e try to use redis on the local machine itself and the  database number 0 on it

So the problem is that, both sidekiq instance you have started, using the same redis server and the database number 0, so causing the conflict and none of them working. So now we have two solutions:

solution 1: configure sidekiq to point to different redis server

solution 2: configure sidekiq to use the same redis server available locally, but make them to use different database and also separate them with namespace

We will go for solution 2 . Let us try something with redis on console before changing sidekiq configuration.

> Redis.new # no options is passed
=> #<Redis client v3.0.4 for redis://127.0.0.1:6379/0> # o number database being used
> Redis.new(db: 1) # database 1 is paased
=> #<Redis client v3.0.4 for redis://127.0.0.1:6379/1> # 1 number database being used
> Redis.new(db: 4)
=> #<Redis client v3.0.4 for redis://127.0.0.1:6379/4> 4 number database being used

Here, you can see that, your redis server is running at 127.0.0.1:6379 and number after / is the database number

So now we can introduce below line in config/initializer/sidekiq.rb file of both the project

config.redis = { :namespace => ‘ThirdPillar’, :url => ‘redis://127.0.0.1:6379/0′ }

config.redis = { :namespace => ‘Barcelona’, :url => ‘redis://127.0.0.1:6379/1′ }

The namespace can have any value, but as convention I have keep the name same as the folder name of the project. So the Barcelona will use datbase 1 of the redis server at redis://127.0.0.1:6379 . The modified configuration files for Barcelona look as below.

config/initializer/sidekiq.rb

require 'sidekiq'
require 'sidekiq-status'

Sidekiq.configure_client do |config|
  config.client_middleware do |chain|
    chain.add Sidekiq::Status::ClientMiddleware
  end
  config.redis = { :namespace => 'Barcelona', :url => 'redis://127.0.0.1:6379/1' }
end

Sidekiq.configure_server do |config|
  config.server_middleware do |chain|
    chain.add Sidekiq::Status::ServerMiddleware, expiration: 30.minutes # default
  end
  config.redis = { :namespace => 'Barcelona', :url => 'redis://127.0.0.1:6379/1' }
end

Make similar change in sidekiq.rb of the other project. Restart the sidekiq on both the project, both will strat working  :)

Reference:
https://github.com/mperham/sidekiq/wiki/Advanced-Options

http://rubydoc.info/gems/sidekiq/Sidekiq

http://redis.io/topics/quickstart


Leave a comment

ruby

This post will contain link to all the post I have written within ruby category . I find lack of this support in wordpress. when you click any link within a category(say ruby), it open up all the post on single page, and you have to scroll down a lot to find a particular topic. Ideally it should have just provided links to the post within a particular category. Since it is not doing that, I have made a index file for all the categories.

Below are my post on ruby :

self receiver and ancestorarguments in rubymethods in ruby ,

difference between private protected public in ruby , ruby block : difference between yield &block ,

proc and lambda , require and load , attr_reader attr_writer attr_accessor in ruby ,

exception handling in ruby rails , difference between dup and clone .


Leave a comment

arguments in ruby

In this post we will look into arguments in ruby. arguments are the values a method expecting when the method is called. The number of values to be passed and its type is fixed at the time of method definition and is called parameter list.

Parameter : They are variables associated with method at the time of defining it. It decides the number of values and its type which need to be passed at the time a method is called. Each parameter name must be unique in the parameter list.Parameters are positional: they describe the argument in the corresponding position of the argument list. The correspondence isn’t one‐to‐one, as we will see below, but each parameter consumes as many arguments as it can, leaving those that remain for the following parameters.

Arguments : The values passed to the method when it is called. They need to be passed according to the parameter list

To discuss various type of arguments, let create argument_demo.rb file and call different methods in the ruby console.

class ArgumentDemo
  # in ruby argument are passed by reference rather then value
  def demo_pass_by_referance(ref_var)
    substituted_val = ref_var.gsub!("a", "1")
    puts substituted_val
  end

  # in ruby you do not need to define the type of parameter 
  # i,e int, string etc.it get defined dynamically by ruby based 
  # on the passed value at time of method call
  # NOTE: ruby is a dynamically typed language

  def i_need_required_argument(house, street, city, post)
    puts "I exactly need 4 arguments"
  end

  #default value is provided in the start
  def start_with_default(house =12, street ="gandhi road", city, post)
    puts "house => #{house} ,street => #{street}, city => #{city}, post => #{post}"
  end

  # default value is provided at the end
  def end_with_default(house, street, city = "UP", post = 122341)
    puts "house => #{house}, street => #{street}, city => #{city}, post => #{post}"
  end

  # method with any number of arguments
  def variable_arguments(*args)
    args.each do |arg|
      puts arg
    end
  end

  # argument as key => value pair
  def named_arguments(args = {})
    puts args[:house]
    puts args[:street]
  end

  # method supporting block argument
  def block_arguments(any_value)
    if block_given?
      yield
    else
      raise "You must pass a block"
    end
  end

end

Let us load the above file on irb and try out calling different methods with different type of argument

$irb #open irb
> load “/home/arun/Desktop/argument_demo.rb” #load the file
true

Before we read about different types of argument, we should understand that in ruby the arguments are always passed by reference not the value. It means that if the argument get modified by the method, its actual value also get modified. See the below output on the console

> my_name = “arun” 
=> “arun”
> @argumnets = ArgumentDemo.new
=> #<ArgumentDemo:0x9b15400>
> @argumnets.demo_pass_by_referance(my_name)
1run
1.9.3p194 :011 > my_name
=> “1run”

So you can see that you have set the variable my_name with value arun. You passed the my_name variable as a argument to method demo_pass_by_referance, which modify the variable my_name inside it. But when you go outside the method and again try to see the value of my name, you see that now my_name is containing the modified value. This show that, here the my_name is not containing value arun but a reference to this value, so any modification on my_name actually change the referred value.

NOTE  : never modify any variable passed as argument to any method directly, specially if it is also passed to other method . I can give a real case example in terms of params. params in rails store all the values passed with a request to a controller and is accessible throughout the controllers and used to pass as argument to many of the controller methods. Once I did the above things i,e params[:auth_token].gsub!(“_”, “-“) in one of my method and it break the whole authentication system of  my application as the above line corrupt the token which is referenced by many other methods. So whenever you want to modify any argument in a method perform the action on duplicate copy of the argument i,e using dup. So using params[:auth_token].dup.gsub!(“_”, “-“) will not change the referenced value as the operation is performed on the copy of argument.

With the above discussion, Now ,We will experiment with arguments by calling different methods in above file on irb console.

1 => Required Argument :

  1. These are the argument which must be passed when the method is called
  2. passing lesser number of argument as defined in parameter list will throw argument error
  3. nil and false are as valid an argument as any other. If a method requires an argument and nil is supplied in its place, Ruby will not complain. Methods wishing to prohibit such values must do so themselves.

See the below output on irb console

> @arg_demo = ArgumentDemo.new
=> #<ArgumentDemo:0xa276320>
> @arg_demo.i_need_required_argument(12, “chandni chowk”, “Delhi”, 11106)
I exactly need 4 arguments
> @arg_demo.i_need_required_argument(12, “chandni chowk”, “Delhi”)
ArgumentError: wrong number of arguments (3 for 4)
> @arg_demo.i_need_required_argument(12, “chandni chowk”, false, nil)
I exactly need 4 arguments

2 => Optional Argument

  1. If the parameter are given default value, it become optional i,e the method will not complain if the corresponding argument is not passed.Say if a method have 4 parameter and 2 are given default value then argument error will occur if you pass less then or more then 2 argument.
  2. If default value is passed to parameters,  all the default value should be either from start or towards the end. if you put the default value in between, it will give syntax error when the file is loaded or compiled
  3. If no of passed argument is equal to the no of parameter, all the default values will be overridden.
  4. When default parameters are defined towards the end, the passed arguments are assigned to them following the know convention i,e left to right, say the method have 4 parameters in which last two have default value and you pass 3 argument, then these argument is set to first 3 i,e default value of 3rd will be overridden and only the 4th parameter will have the default value
  5. When you set the default parameter at the beginning, it create confusion in assignment of argument to them as far as I have understand.This is how they are getting assigned. Non default parameter are assigned right to left, the remaining arguments are now assigned to the default parameter from left to right as usual.

Below output can illustrate the above points

> @argumnets = ArgumentDemo.new
=> #<ArgumentDemo:0x8988a70>
> @argumnets.start_with_default(“UP”,”2342″) # two argument passed
house => 12 ,street => gandhi road, city => UP, post => 2342  #assigned to the last two non default parameter

> @argumnets.start_with_default(“my street”,”UP”,”2342″) # 3 argument passed
house => my street ,street => gandhi road, city => UP, post => 2342 # last 2 i,e “UP”,”2342″ assigned to city and post following right to left rule and the remaining one i,e “my street” is assigned to the first parameter house following left to right rule

> @argumnets.start_with_default(32,”my street”,”UP”,”2342″) # 4 argument passed so assigned as usual following left to right rule , infact if no of passed argument is equal to the number of parameter bot rule i,e left to right or right to left will give same result
house => 32 ,street => my street, city => UP, post => 2342

> @argumnets.end_with_default(32, “my_street”) # 2 argument passed
house => 32, street => my_street, city => UP, post => 122341 # first two are assigned following left to right rule

> @argumnets.end_with_default(32, “my_street”, “Patna”) # 3 argument are passed
house => 32, street => my_street, city => Patna, post => 122341 # first 3 are assigned following left to right rule

> @argumnets.end_with_default(32, “my_street”, “Patna”, “5643”) # 4 argument are passed
house => 32, street => my_street, city => Patna, post => 5643 # first 4 are assigned following left to right rule

NOTE : Always keep the parameter with default value towards the end

3 => Variable list Arguments

  1. They are created by defining single parameter preceded by * . They are also known as spat arguments
  2. Any number of arguments can be passed separated by comma
  3. In the method they are available as an array

Below output can illustrate the above point.

> @argumnets = ArgumentDemo.new
=> #<ArgumentDemo:0x89d1784>
> @argumnets.variable_arguments(1, “arun”, 3)
1
arun
3
> @argumnets.variable_arguments(1, “arun”, 3, “kapil”)
1
arun
3
kapil
>

4 => Named Arguments

  1. They are defined as a hash with argument being passed as key => value pair
  2. The advantage is that These arguments are not positional thus you do not need to remember to pass a particular value at particular position.
  3. It support variable list argument i,e you can pass any number of arguments.
  4. Disadvantage is that it do not give argument error if user pass no or wrong number of argument. It has to be handle by you in the code.

1.9.3p194 :048 > @argumnets = ArgumentDemo.new
=> #<ArgumentDemo:0x8a44018>
1.9.3p194 :050 > @argumnets.named_arguments({:house =>12, :street => “xyz street”})
12
xyz street

5 => Block Arguments

  1. They are defined by putting & before the parameter name . It has to defined after defining all other parameters including the default one
  2. While calling the method, you should pass the block argument after closing parenthesis of the arguments i,e method(arg1, arg2..){}
  3. They do not contributes to argument count , so No argument error is thrown. You can check it with block_given? method and raise exception to user for passing the block
  4. Block arguments are used in method with yield keyword . read more about block in this post.

> @argumnets = ArgumentDemo.new
=> #<ArgumentDemo:0x8a5e6ac>
1.9.3p194 :066 > @argumnets.block_arguments()
ArgumentError: wrong number of arguments (0 for 1)
> @argumnets.block_arguments(232){puts “Iam passed as a block”}
Iam passed as a block
> @argumnets.block_arguments(232)
RuntimeError: You must pass a block

=> Arity
The arity of a method is the number of arguments it takes. If the method expects a fixed number of arguments, this number is its arity. If the method expects a variable number of arguments, its arity is the additive inverse of its parameter count. Methods implemented in C, i.e. most core methods, have an arity of -1 if they accept a variable number of parameters. It follows, then, that an arity ≥ 0 indicates a fixed number of parameters; a negative value, a variable number. Method and Proc objects have #arity methods which return the arity for the method/proc it objectifies.

Classification by Arity

Methods with fixed arities can be classified as follows: A unary method expects exactly one operand (its receiver), a binary method requires two (its receiver and one argument), ternary-method requires exactly three (its receiver and two arguments), an n-ary method requires n operands (its receiver, and n-1 arguments).

Follow

Get every new post delivered to your Inbox.