Attribute accessors in ruby – behind the scene

In the last post we saw that, what attribute accessors methods are and how it can be used. In this post, we’ll see how actually these accessors are implemented.

lets take the example from last post and see why errors were thrown in some cases :-

  
class Person
  attr_accessor :age
  attr_writer :name
  attr_reader :gender
 end 
1.9.3-p125 :013 > p = Person.new
=> #<Person:0x00000001309c00> 
1.9.3-p125 :014 > p.age=20
=> 20 
1.9.3-p125 :015 > p.age
=> 20 
1.9.3-p125 :016 > p.name='vikram'
=> "vikram" 
1.9.3-p125 :017 > p.name
NoMethodError: undefined method `name' for #<Person:0x00000001309c00 @age=20, @name="vikram">
	from (irb):17
	from /home/inbelu013521a/.rvm/rubies/ruby-1.9.3-p125/bin/irb:12:in `'
1.9.3-p125 :018 > p.gender
=> nil 
1.9.3-p125 :019 > p.gender='male'
NoMethodError: undefined method `gender=' for #<Person:0x00000001309c00 @age=20, @name="vikram" >
	from (irb):19
	from /home/inbelu013521a/.rvm/rubies/ruby-1.9.3-p125/bin/irb:12:in `'

Lets analyze all three accessor methods one by one and see what is happening behind the scene.
In above example we saw that, we can read and write the attribute age, only write the attribute name and only read the attribute gender and that happens because behind the scene ruby translates the method call

attr_accessor :age

into

def age=(value)
  @age = value
end
def age
  @age
end
attr_writer :name

into

def name=(value)
  @name = value
end
attr_reader :gender

into

def gender
  @gender
end

So, now it makes clear that why those method calls were throwing error.

Attribute accessors in ruby

As we all know that ruby is an object oriented language and we always deal with classes and objects directly or indirectly with it. Now when we deal with objects, we certainly have one or more attributes associated with it which is like an instance variable and can be accessed using the object dot notation.

To access the attributes of an object, like any object oriented language, we need to have getters & setters method and ruby does not make any difference between getters & setters methods and normal methods. Let’s see an example of getters and setters in ruby.

Suppose we have to define a class person with an attribute called age, the class skeleton with getter & setter method will look like the code given below :-

class Person
  def age=(age)
    @age = age
  end

  def age
    @age
  end
 end 
1.9.3-p125 :020 > p = Person.new
=> #<Person:0x000000012cc6e8> 
1.9.3-p125 :021 > p.age=20
=> 20 
1.9.3-p125 :022 > p.age
=> 20  

Now these above getters & setters methods are called attribute accessor methods in ruby.

As we know that ruby does so many things on its own(one of the main reasons i love it), by default it has given some accessor methods which serves their own purpose. The accessors that ruby provides by default are attr_accessor, attr_reader and attr_writer. Lets see how they work :-

    
class Person
  attr_accessor :age
  attr_writer :name
  attr_reader :gender
 end 
1.9.3-p125 :013 > p = Person.new
=> #<Person:0x00000001309c00> 
1.9.3-p125 :014 > p.age=20
=> 20 
1.9.3-p125 :015 > p.age
=> 20 
1.9.3-p125 :016 > p.name='vikram'
=> "vikram" 
1.9.3-p125 :017 > p.name
NoMethodError: undefined method `name' for #<Person:0x00000001309c00 @age=20, @name="vikram">
	from (irb):17
	from /home/inbelu013521a/.rvm/rubies/ruby-1.9.3-p125/bin/irb:12:in `'
1.9.3-p125 :018 > p.gender
=> nil 
1.9.3-p125 :019 > p.gender='male'
NoMethodError: undefined method `gender=' for #<Person:0x00000001309c00 @age=20, @name="vikram" >
	from (irb):19
	from /home/inbelu013521a/.rvm/rubies/ruby-1.9.3-p125/bin/irb:12:in `'

So, from the above snippets, it is clear that we can read and write the attribute age, can only write the attribute name and can only read the attribute gender and we can generalize it by saying that

    
class Person
  attr_accessor :age   # provides getters & setters
  attr_writer :name    # provides only setters
  attr_reader :gender  # provides only getters
end 

I think above paragraphs make it clear about the different accessor methods and when & how to use it.

In the next post I’ll describe about behind the scenes for these methods.

Cheers :)

Method Chaining and its benefits in ruby

Being a rails/ruby developer, we do method chaining every day but many of us are unaware of the term.

Let me give you a simple example of method chaining :-

User.where(SOME_CONDITION).order(SOME_FIELD)

yes, that is method chaining. Now, lets define it in standard way.

What is method chaining ?

Method Chaining is a common syntax for invoking multiple method calls. Each method returns an object, allowing the calls to be chained together in a single statement.

How to write code to do method chaining?

Lets start with designing a simple class with some methods. Lets say the class Book.

class Book 
  def title(title)
    @title = title
  end

  def author(name)
    @author = name
  end
  
  def price(price)
    @price = price
  end

  def book_details
    puts "The book titled #{@title} is written by #{@author} and is available at price $#{@price}"
  end
end

Now our class is ready with some basic methods. Lets try to execute the methods and do the method chaining on methods title(), author() and price().

1.9.3-p125 :021 > book = Book.new
 => #<Book:0x00000001f38468>  
1.9.3-p125 :022 > book.title("Method Chaining in Ruby")
 => "Method Chaining in Ruby" 
1.9.3-p125 :023 > book.title("Method Chaining in Ruby").author("Vikram Kumar Mishra")
NoMethodError: undefined method `author' for "Method Chaining in Ruby":String

:(…throwing error :). Well it was expected but what’s wrong with the code written? If you see the error carefully, it is trying to call the author() method on the string “Method Chaining in Ruby” because the title() method is returning the string and so the error is. Basically if we want to call any instance method, we should have the instance first, right? Yes. Lets modify our methods a bit.

class Book 
  def title(title)
    @title = title
    self
  end

  def author(name)
    @author = name
    self
  end
  
  def price(price)
    @price = price
    self
  end

  def book_details
    puts "The book titled #{@title} is written by #{@author} and is available at price $#{@price}"
  end
end

lets try chaining the method again

1.9.3-p125 :044 > book = Book.new
 => #<Book:0x00000001f38468> 
1.9.3-p125 :045 > book.title("Method Chaining in Ruby")
 => #<Book:0x00000001f38468 @title="Method Chaining in Ruby"> 
1.9.3-p125 :046 > book.title("Method Chaining in Ruby").author("Vikram Kumar Mishra")
 => #<Book:0x00000001f38468 @title="Method Chaining in Ruby", @author="Vikram Kumar Mishra"> 
1.9.3-p125 :047 > book.title("Method Chaining in Ruby").author("Vikram Kumar Mishra").price(100)
 => #<Book:0x00000001f38468 @title="Method Chaining in Ruby", @author="Vikram Kumar Mishra", @price=100> 
1.9.3-p125 :048 > book.title("Method Chaining in Ruby").author("Vikram Kumar Mishra").price(100).book_details
The book titled Method Chaining in Ruby is written by Vikram Kumar Mishra and is available at price $100
 => nil

Whoa…it worked..yay :)

Benefits of method chaining:

1) Improves the readability of the code.

2) Reduces the amount of code needed when interacting with a class or an instance of a class.

3) Eliminates the need for intermediate variables.

Useful, isn’t it? :)

Reference :- Method Chaining-SitePoint

Difference between map, each, select and collect in ruby

In ruby we have some predefined iterators which we use everyday in practice to iterate ever an collection of data and those are map, collect, each and select. Let’s see how they differs with each others :-

Suppose we have an array of numbers like [1,2,3,4] and we will use all those predefined iterators on this array and will see the difference in result.

1.9.3-p125 :029 > a = [1,2,3,4]

=> [1, 2, 3, 4]

1.9.3-p125 :030 > a.map{|n| n*22}

=> [22, 44, 66, 88] #operates on each element of the array and returns the result

1.9.3-p125 :031 > a.map{|n| n>22}

=> [false, false, false, false] #operates on each element of the array and returns the result

1.9.3-p125 :032 > a.collect{|n| n*22}

=> [22, 44, 66, 88] #operates on each element of the array and returns the result

1.9.3-p125 :033 > a.collect{|n| n>22}

=> [false, false, false, false] #operates on each element of the array and returns the result

1.9.3-p125 :034 > a.select{|n| n*22}

=> [1, 2, 3, 4] #operates on each element of the array and ignores the result because we are not selecting anything.

1.9.3-p125 :035 > a.select{|n| n>22}

=> [] #operates on each element of the array and returns the selected result

1.9.3-p125 :036 > a.each{|n| n*22}

=> [1, 2, 3, 4] #operates on each element of the array and ignores the result

1.9.3-p125 :037 > a.each{|n| n>22}

=> [1, 2, 3, 4] #operates on each element of the array and ignores the result

1.9.3-p125 :038 > a

=> [1, 2, 3, 4] #array is unchanged

From the result, we can see that map and collect are one and the same and differs from each and select method.

The select method returns the result of the code block if it is selective i.e. we are writing the code to return the conditional result.

When to use what

Map OR Collect – When we need to operate on existing data and get the result. For example :-

a.collect{|n| n*22} #[22, 44, 66, 88]

a.map{|n| n*22} #[22, 44, 66, 88]

select – When we need to select one or more data from a collection of data based on certain condition. For example :-

a.select{|n| n>22} #[]

a.select{|n| n>2} #[3,4]

a.select{|n| n<2} #[1]

each – When we need to call any other method/block on each element of the array. For Example :-

a.each{|n| print n} #1234

a.each{|n| do_something(n)}

Easy and powerful, right? :) That’s why I love ruby :)

Send inline image in email with rails

There are situations, when we need to send images as inline images, not as attachment via rails application. I also recently faced similar need. dig around and brought up the solution for you all and its very simple.

In mailer method, write the following line :-

attachments.inline["what_ever.image_format"] = File.read("Path to image")

For Example, in notifier_mailer.rb, I have

def send_admin_statistics param1, param2
  .............................
  .
  .
  attachments.inline["what_ever.image_format"] = File.read("Path to image")
  .
  .
  .............................
end

and in corresponding view of mailer method, add the line

  <%= image_tag(attachments["what_ever.image_format"].url) %>  

Like in app/views/notifier_mailer/send_admin_statistics.html.erb, I have

  ..............................
  .
  .
  <%= image_tag(attachments["what_ever.image_format"].url) %>
  .
  .
  ..............................

Simple, isn’t it? :D

Cheers
Vikram

Deprecation Warning for vendor plugins in rails 3.2 and higher versions OR Convert simple rails 2.3 style plugins

As we all know that till rails 3.1, we were able to use vendor-ed plugins by keeping the code for any plugin in vendor/plugins directory. But, using vendor-ed plugins is deprecated in rails versions 3.2+ and throws the deprecation warning for the same. In rails 4, it will be completely removed.  So, its a big headache when we try to upgrade any application with version rails 3.1 or lesser to rails versions 3.2.0 and higher.  So, if you are like me, do not worry. Every problem has a solution and so does for it also :) .

If you have plugins in your vendor/plugins in directory then try to replace that plugin with a gem, which serves the same purpose as the plugin does. If you can not find any equivalent gem for your plugin or any alternative does not exist or you do not want make any changes in the code-base, please follow the steps on the below given link :-

http://matt.coneybeare.me/how-to-convert-simple-rails-23-style-plugins/

Thanks

Vikram

Disable page caching in all browser

Many times we face some serious issue while dealing with web page visibility after and before login and that happens due to browser’s property to cache pages.

Here is the solution to avoid browser caching problem using HTML and rails 3 :-

In application_controller.rb add

  before_filter :set_cache_buster

  def set_cache_buster
   response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
   response.headers['Pragma'] = 'no-cache'
   response.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT'
  end

But above solutions does not work for all browsers. Like you will still face issue in browser like safari and in some versions of IE too. So to avoid it all, in layouts/application.html.erb

  <body onunload="">

Now, it will work like a charm…cheers :)