Test for nil, empty or blank
x.blank?Trap" ".empty? is false, and nil.empty? raises NoMethodError.
self, the current object.include, prepend and extend change where a module sits in that chain.nil and false are falsy. 0, "" and [] are all truthy.x.blank?Trap" ".empty? is false, and nil.empty? raises NoMethodError.
"Hi #{name}"'Hi #{name}'to_s, with or without a newline, return nilputs xprint xinspect, return the valuep xTipRuby stores each :symbol once, so comparing two is an identity check. Use them for hash keys and fixed labels, and strings for user text.
user_name, UserAccount, MAX_USERSempty?save!Asked in interviews
AskedWhat are Ruby's naming conventions?1.eql?(1.0)a.equal?(b)case does(1..10) === 5Tip1 == 1.0 is true, but 1.eql?(1.0) is false. If you define == on a value object, define eql? and hash too.
Trap=== isn't symmetric. String === "hi" is true, but "hi" === String is false.
obj.freeze# frozen_string_literal: trueobj.dupobj.cloneStruct.new(:x, :y)Data.define(:x, :y)Trapfreeze, dup and clone are all shallow. For plain data, Marshal. makes a deep copy.
a.map { |n| n * 2 }a.select(&:even?) a.reject(&:even?) a.partition(&:even?) a.flattena.compactTrapeach runs the block for side effects and ignores its result, so a.each { |n| n * 2 } still returns a.
a.merge(b)a.merge!(b)TipWhen a key is in both, the argument's value wins unless a block picks one. update is another name for merge!.
Asked in interviews
AskedExplain the difference between Hash#merge and Hash#merge!map and select from your eachinclude Enumerablea <=> b(1..).lazy.map { |n| n * 2 }.first(5)Tipsort, min and max use each element's <=>. Define it and include Comparable to get the comparison operators.
Proc.new { |x| x }->(x) { x * 2 }TipA lambda checks its argument count and raises ArgumentError. A proc fills missing arguments with nil and drops extras.
Trapreturn in a proc exits the method that defined it. In a lambda it exits only the lambda.
Asked in interviews
AskedWhat is the difference between a block, proc, and lambda?yield if block_given?def run(&block)block.callTipPass it on with other(&block). If the value after & isn't a proc, Ruby calls to_proc, which is how &:upcase works.
Trapyield with no block raises LocalJumpError. A &block parameter is just nil.
_1, or it in 3.4+a.map { it * 2 }5.then { |x| x * 2 }user.tap { |u| u.save }Tipyield_self is another name for then. To chain your own methods, return self from each one.
TrapIf a method returns a number, not self, the next call goes to an Integer and raises NoMethodError.
def f(name:, age: 18)f(**opts)def double(x) = x * 2TrapSince Ruby 3.0 a hash stays positional, so foo({key: 1}) raises ArgumentError when foo takes only keywords.
def f(*args, **opts)f(*list)def wrap(...)run(...)Traprun(*args, **opts) passes no block. Add &block.
in {name:, age: 18..}data => {name:}data in {status: 200}TipHash patterns match even with extra keys, and ^x matches an existing variable's value.
TrapWith no matching branch and no else, Ruby raises No.
include Flyableobj.respond_to?(:speak) TipA module has no new and no subclasses. It's a mixin or a namespace, like Billing::Invoice.
TrapDuck typing means code depends on what an object can do, not its class. A wrong object fails only at run time, with NoMethodError.
attr_reader, attr_writer, attr_accessor@name@@count@countTipself is the instance in an instance method, the class in a class body, and main at the top of a file.
TrapInside a class, name = value creates a local variable. Write self.name = value to call the setter.
protectedself. (2.7+)privatepublic :secretTrapsend can still call a private method, so visibility isn't a security boundary.
supersuper()alias_method :size, :lengthTrapsuper() raises ArgumentError when the parent method requires an argument.
include Modprepend Modextend ModChild.ancestorsdef str.shoutTipClass methods are singleton methods of the class object. class << self opens its singleton class.
Trapancestors leaves out the singleton class, which Ruby checks first.
Asked in interviews
AskedWhat is the difference between include, prepend, and extend?module_functionincludealias greet_a greetTipUse extend self when included methods should stay public.
TrapWhen two modules define a method, the last one included wins, because ancestors lists it first.
define_method(name) { |v| v }method_missingrespond_to_missing? TipPrefer define_method when you know the names in advance. It's faster than method_missing and shows up in methods.
TrapCall super for every name you don't handle, or a typo stops raising NoMethodError.
Asked in interviews
AskedWhat is metaprogramming in Ruby?String.class_eval { def a; end }obj.instance_eval { def a; end }refine String dousing PatchesTipA refinement's scope is lexical, so code in another file doesn't see it.
TrapOn a class the result looks reversed, because String. defines a class method.
Asked in interviews
AskedWhat is the difference between class_eval and instance_eval?TipA return inside ensure replaces the result and swallows any exception. Inside rescue, retry runs the body again.
Traprescue Exception also catches Interrupt and SystemExit, so Ctrl+C and exit can stop working.
catch(:done) { throw :done }KeyErrorh.fetch(:a)data ||= defaultTrapSubclass StandardError. A class that inherits straight from Exception slips past a bare rescue.
File.open("f") { |f| f.read }File.new("f")system("ls")`ls`exec("ls")TipWith user input, write system("ls", dir), so no shell runs.
TrapA missing file raises a SystemCallError, not an IOError. File.exist? is only a hint, so still rescue.
require 'json'load 'config.rb'bundle installbundle updatebinding.breakbyebugTipThe Gemfile lists accepted version ranges, and Gemfile.lock the exact versions. Commit both. binding.irb opens a console at that line.
Traprequire './x' breaks when the program starts from another directory. Use require_.
Thread A releases the GVL while it waits on I/O, so thread B runs. A Ractor has its own GVL and runs at the same time.
Ractor.new { work }TipMRI calls the lock the GVL, not the GIL. Ruby 4.0 replaced Ractor#take with Ractor#value.
TrapRactors are still experimental, so production CPU work usually runs in several processes.
Asked in interviews
AskedWhat is the Global Interpreter Lock (GIL) in Ruby?Fiber.new { Fiber.yield }Async { fetch(url) }m.synchronize { n += 1 }Queue.newTipThreads are preemptive, and fibers are cooperative.
TrapThe GVL doesn't prevent race conditions. A thread can switch in the middle of @n += 1.
Asked in interviews
AskedWhat is the difference between Thread and Fiber in Ruby?ObjectSpace.dump_all @r ||= computeruby --yjit app.rbBenchmark.measure { work }stackprofvernierTipMark-and-sweep frees cycles too. Minor collections mark only young objects.
TrapA leak is an object that stays reachable, like a cache that only grows. Circular references aren't a cause.
def call(env)bin/rails middlewareTipA request passes down the middleware stack to the router, then a controller action. Keep business rules in models.
redirect_to @userrender :new, status: :unprocessable_entity params.require(:user).permit(:name) params.expect(user: [:name])Traprender :new doesn't run the new action. It keeps this action's instance variables, and a redirect loses them.
User.includes(:posts) LEFT OUTER JOINUser.eager_load(:posts) scope :active, -> { where(active: true) }TipA scope always returns a relation, so it chains. A class method that returns nil breaks the chain.
Trapcount always runs a SQL COUNT, even on loaded records. Use size on a preloaded association.
has_many :groups, through: :membershipshas_and_belongs_to_many :groupsdependent:user.destroyDELETEuser.deleteTrapdelete skips callbacks and associated records, which can leave orphaned rows.
after_create_commit :send_emailextend ActiveSupport::Concern SignUp.new(params).call TipA concern still adds methods to the model. A service object moves the logic out.
TrapWith after_create, the email goes out even if the transaction later rolls back.
ActiveRecord::Base.transaction dolock_versionorder.with_lock { ship }Tipraise Active undoes the block quietly.
TrapPlain save returns false without raising, so the other write still commits. Use save! inside the block.
allow(u).to receive(:email)expect(m).to receive(:send_email) build(:user)create(:user)TipFixtures are YAML records that load once, so they're fast but shared. Factories keep each test's data next to the test.
def initialize(mailer = Mailer.new)a.b.c behind one method (Rails)delegate :street, to: :addressTipComposition is the usual choice in Ruby. Use inheritance when the subclass really is a special kind of the parent.
Config.instanceinclude SingletonTrapA singleton is global state, so one test can affect another.
User.where(name: params[:name])encrypts :ssnTipRails escapes view output, so XSS risk sits in html_safe and raw. An authenticity token blocks CSRF.
TrapMarshal.load on untrusted data can lead to remote code execution.
Asked in interviews
AskedHow do you securely handle sensitive data in Ruby?Nothing matches. Try a shorter word, or clear the search.
With Pro, you can:
Already have Pro? Sign in