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 :)

Autoloading modules or classes from lib directory rails 3

From the title of this post, it seems that this is too easy to do and it indeed is but common too. However in some cases especially in production environment, it becomes a serious headache and this is my personal experience which I faced yesterday.

It is a very common problem for developers using rails 3 that they are not getting the modules or classes from their lib directory loaded in Rails 3, especially in production. This leads to errors like “NoMethodError”, “No such file to load”, and “uninitialized constant” etc. I also faced the same and googled it and found many of the posts for this problem with different reasons and different solutions. So, I am trying to summarize the basic fixes for it.

1) Your lib directory is not included in your autoload path.
In Rails 2, classes and modules were auto loaded but in rails 3, it has been updated such that classes and modules are lazy loaded. So a class/module wont be loaded to your application until you require it. A easy solution to this is to include lib folder and its sub folders in autoload paths. Just open the file config/application.rb and insert the line

  config.autoload_paths += %W(#{config.root}/lib)
  config.autoload_paths += Dir["#{config.root}/lib/**/"]

2) Your class/module is not named correctly
Remember the quotation, convention over configuration. Please follow the classes/modules naming standard in rails way. i.e. if there is a class named ClientUser, then file name should be client_user.rb and vice versa.

3) Your application is threadsafe.
This was the solution to my problem. If you have threadsafe enabled in production environment, then the classes/modules will not be autoloaded even if they are included via autoload path. So, to workaround this either require your library files or comment out the line config.threadsafe! from config/production.rb.

Hope it will help! :)

finding subsets of an array in ruby

Lets say we have to find all subsets of specific length from an array. The very first thing that will hit our mind is ohh no.. :(, now i will have to write more complex logics and all. But don’t worry, ruby provides a simple method for doing it. Now happy?? :). Ok, let me show you how it works.

Lets say we have an array [a,b,c,d,e,f,g,h,i,j,k,l] and need to find all subsets of length 2 to 5. So here we go

  
  our_array = [a,b,c,d,e,f,g,h,i,j,k,l]
  our_required_subsets = 2.upto(5).flat_map { |n| our_array.combination(n).to_a } 

  our_required_subsets.each do |subset|
  
    print subset
    print "\n"

  end

Easy isn’t it ? That’s why I love ruby :) .