Ultimate cheat sheet for Ruby and ROR developers

Sometimes it feels hard to remember keyword and namings are very difficult when you are becoming experienced developer. Especially every 5 years, abstraction of computer science is drastically getting changed. So, more abstraction means more keyword and naming.

I know there are some peoples really remembers everything they read or what they did in the past.

But I think most of developers always learning new things and keep forgetting what they did or what they were doing.

One of my coworkers has a huge long list with blogs and private Github repo which are containing what he read from the book and what he did in the past.
And sometimes he was like digging his “memo” copy pasting some code from his repo. It was a bit fun to see when he says “please wait few moment” and digging his repositories.

But I think it’s okay to forget those things since you are not using anymore, because that will makes less stressful. However, I think we (developers) should able to easily recap and catchup new technologies when we need it.

With this article I would like to share my Ruby and ROR cheat sheet as an article. And I hope this will help some developers to recap Ruby and ROR. This article has mostly concentrated on examples instead of explanations. So, if you have more questions it will be always good to check Ruby API docs or books.

Special operators from Ruby language

Pipe |> : Instead of dot. you can use pipe to call methods.

Binary operators:

 a    =  0011 1100 # a is 60
b = 0000 1101 # b is 13
------------------
a&b = 0000 1100 # binary AND, the result is 12
a|b = 0011 1101 # OR, the result is 61
a^b = 0011 0001 # XOR, the result is 49
~a = 1100 0011 # Flip bits, the result is -14
Also
<<, >> binary left and right shift. I never used this one

And sometimes XOR might be useful.

Logical operators:

In Ruby nil, false— is logical false state, 0, true and any other values are local true state. With this condition following logical operators are works as other language.

and, && is and operator
or, || is or operator
not, ! is not operator

Include vs Export

module HelperMethods
def say_hello
puts 'hello'
end
end
class ExtendHere
extend HelperMethods
end
class IncludeHere
include HelperMethods
end
ExtendHere.say_hello
IncludeHere.new.say_hello

Proc vs Lambda

# Lambda with argument
my_lambda = lambda { |arg|
puts "Here is arguments #{arg}"
return "it's finished"
}
my_lambda.call("<I'm the argument>")
=> Here is arguments <I'm the argument>
=> "it's finished"

Proc return and argument

# Proc with argument
my_proc = proc do |arg|
puts "Arguments: #{arg}"
end
my_proc.call('Proc argument')
=> Arguments: Proc argument# Proc return where it's declared not from where it's getting called
def call_my_proc
local_proc = proc do
return 'will return from context'
end
local_proc.call
end
puts call_my_proc
=> will return from context# But if you try to return directly from the proc
my_proc = proc do |arg|
return arg
end
puts my_proc.call('Return this')
# You will get an error, because it's trying return current context and if return not allowed then you will get this.
=> LocalJumpError (unexpected return)

Proc will carry variable from context were declared

# Proc current context
def call_proc(my_proc)
count = 500
my_proc.call
end
count = 1
my_proc = proc { puts count }
puts call_proc(my_proc)
=> 1

Raise, fail and throw

“raise” will used for re-raise, fail is not. “throw” is useful when you have very nested logics which always need to return to original block always.

“raise” will automatically re-raise original issue

def raise_issue
raise 'raising issue'
end
def re_raise
begin
raise_issue
rescue
puts 'rescued once and going to re-raise'
raise
end
end
# You can write code without begin if you need to rescue whole method itself.
def handle_raised_issue
re_raise
rescue => e
puts "original raised issue was: #{e.class}, #{e.message}"
end
# Raise
handle_raised_issue
=> rescued once and going to re-raise
=> original raised issue was: RuntimeError, raising issue

“raise” and “fail” are same. But official documents are suggesting to use raise always.

def fail_issue
fail 'fail issue'
end
def try_re_fail
fail_issue
rescue
puts 'rescued once and going to re-fail'
fail
end
def handle_failed_issue
try_re_fail
rescue => e
puts "original failed issue was: #{e.class}, #{e.message}"
end
# Raise
handle_failed_issue
=> rescued once and going to re-fail
=> original failed issue was: RuntimeError, fail issue

“throw” will caught by nearest catch block when keyword matches

def throw_catch
catch :some_error do
puts 'Going to throw an error'
throw :some_error
end
end
# Throw
throw_catch

Singleton class aka Eigenclass

class MyClass
def ins_method
puts "I'm instance method"
end
end
def MyClass.my_singleton
puts "You can't see where am I located, but you can call me"
end
pry(main)> MyClass.singleton_class
=> #<Class:MyClass>
pry(main)> MyClass.singleton_methods
=> [:my_singleton, :yaml_tag]
# Object also has singleton class
my_obj = MyClass.new
def my_obj.object_singleton
puts "I'm also a singleton class of object"
end
pry(main)> my_obj.singleton_class
=> #<Class:#<MyClass:0x00007ffd75a53848>>

Instance variables stored into “singleton class” of Ruby

class MyEigenClass
@@singleton_var = []
class << self
def first_singleton
@@singleton_var << 'first_singleton'
end
def second_singleton
@@singleton_var << 'second_singleton'
end
def print_singleton_vars
puts @@singleton_var
end
end
end
pry(main)> MyEigenClass.singleton_methods
=> [:first_singleton, :second_singleton, :print_singleton_vars, :yaml_tag]

Object methods are loaded into memory and everything is an object in Ruby.

class MyClass
def hello_method
puts 'hello instance method'
end
end
my_obj = MyClass.newpry(main)> MyClass.instance_methods(false)
=> [:ins_method, :hello_method]

Monkey patching

class String
def say_hello
puts "hello, #{self}"
end
end
'this is string'.say_hello
=>hello, this is string

Ruby has rich enough built-in methods you always need to check before you write your own.

Built in methods

obj = 'Hello'.chars.each_with_index.inject({}) do |new_obj, (val, indx)|
new_obj[indx] = val
new_obj
end
=> {0=>"H", 1=>"e", 2=>"l", 3=>"l", 4=>"o"}

Reject, map, reverse and other handful built in methods

'I want to eat   apple'.split(' ').reject(&:empty?).map(&:length).reverse
=> [5, 3, 2, 4,sor

sort, sort_by built in sorting methods uses quick sort with ascending order.

# When you customize it you need to use 
[1,3,2].sort{|prev_val, next_val| prev_val <=> next_val # Put ur logic that returns -1,0,1 }
# You will get only single value in block
[{id: 2}, {id:1}].sort_by{|single_val| single_val[:id] }

Ruby on Rails

Include vs Joins (ActiveRecord)

User.joins(:company).to_sql
=> "SELECT \"users\".* FROM \"users\" INNER JOIN \"companies\" ON \"companies\".\"id\" = \"users\".\"company_id\""

`preload` split query into 2 request, one will search by an array of ids which came from the first query.

User.preload(:company)
=> User Load (0.9ms) SELECT "users".* FROM "users" /* loading for inspect */ LIMIT $1 [["LIMIT", 11]]
=> Company Load (1.7ms) SELECT "companies".* FROM "companies" WHERE "companies"."id" IN ($1, $2) [["id", 1], ["id", 2]]

`eager_load` will simply do LEFT OUTER JOIN

"SELECT \"users\".\"id\" AS t0_r0, \"users\".\"name\" AS t0_r1, \"users\".\"company_id\" AS t0_r2, \"users\".\"created_at\" AS t0_r3, \"users\".\"updated_at\" AS t0_r4, \"companies\".\"id\" AS t1_r0, \"companies\".\"name\" AS t1_r1, \"companies\".\"address\" AS t1_r2, \"companies\".\"created_at\" AS t1_r3, \"companies\".\"updated_at\" AS t1_r4 FROM \"users\" LEFT OUTER JOIN \"companies\" ON \"companies\".\"id\" = \"users\".\"company_id\""

`includes` acts differently for different pattern

# It will act as pre_load
User.includes(:company)
=> User Load (0.4ms) SELECT "users".* FROM "users" /* loading for inspect */ LIMIT $1 [["LIMIT", 11]]
=> Company Load (0.4ms) SELECT "companies".* FROM "companies" WHERE "companies"."id" IN ($1, $2) [["id", 1], ["id", 2]]
# When use `where` or `order` will act as eagser_load
User.includes(:company).where(users: { id: 1 })

find_in_batches vs find_each

When the need to use batch operation with ActiveRecord those 2 methods will be very helpful.

ActiveSupport::Concern

When you wanted to extend your model with included do this will help.

What is behind scene of Ruby

--

--

Full stack software engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store