Feb Flash Sale

Ruby on Rails Interview Questions and Answers for 2023

Ruby on Rails is a full-stack framework offering sufficient tools needed to build amazing web apps on both the front and back end. It has gained momentum and left behind all other framework alternatives. Thus, is very popular among developers. Here is a list of the top, expert-curated list of Ruby on Rails interview questions and answers that will help you ace interviews related to Ruby on Rails. It is a dynamic, flexible, and robust framework that has been preferred by several organizations of all sizes and is in great demand. To get a detailed understanding of Ruby on Rail's technical interview questions, you must go for Ruby on Rails training. If you just getting started with RoR, then this guide will help you achieve your goals with detailed information covering questions and answers from freshers to advanced levels with simple coding examples to help you get through concepts.

  • 4.7 Rating
  • 74 Question(s)
  • 35 Mins of Read
  • 6987 Reader(s)

Beginner

Rails is a web application development framework based on the Ruby programming language. It is designed to help developers by making the development work more accessible and streamlined. Rails is a high-level, interpreted programming language compatible with different programming paradigms. Rails, however, is a framework that can be used to build innovative, robust, and secured web applications.

Expect to come across this popular question in the Ruby on Rails interview.

  • Variables: these are used to store some value where all letters are lowercase and underscore separate words. Class and Modules: you can use mixed case without any underscore, and each word must start with an uppercase.
  • Database Table: To name the database, you must use all lowercase letters and underscore between words; also, make sure that the table names are plural.
  • Model: you must use mixed-case, which always has singular with the table name.
  • Controller: you must represent in plural form like OrdersController.

Below are the significant benefits of using RoR for web development. 

  • Clean code with fewer bugs- every code has a single and unambiguous submission, making the code cleaner and easy to debug. It makes the code easier to refactor and restructure.  
  • Best industry standards- RoR is an opinionated framework that automatically guides you to perform specific tasks without issues. It works on the best standards and practices ensuring efficient web development. 
  • The Rails is based on the philosophy- DRY (Do not Repeat Yourself) principle that separates the concerns and maintainability of your application. 
  • MVC model- it is built around the MVC model that makes your app modular and extensible, making it easier for developing complex applications will be easier to extend new features and business logic. 
  • High-speed development offers a vast ecosystem of modules, generator scripts, and an effective and efficient package management system that allows for scaffolding a complex application using a few commands. Also, with the availability of open-source libraries, you can include any functionality. 
  • Low learning curve- it is a preferable choice of framework for beginners as there is not much effort required to get started with developing RoR apps.  

Below are some disadvantages that need to be considered while working with RoR. 

  • Slow speed and performance- due to its slow speed, it is sometimes hard to scale RoR apps. But the case holds if you are developing large or complex applications. The performance issue is primarily due to the server or database architecture, not RoR. 
  • Less flexible apps- due to complex dependencies and modules, the developers need to figure out all the required dependencies to include while starting the project. This fits well for developing a standard app but is unsuitable for unique ideas.  
  • Documentation- the test suites act as documents for RoR libraries and gems. It is good to have code and examples, but sometimes it is difficult to indulge in the code. 

Below are the use cases where RoR is the perfect fit. 

  • For developing online stores with simple browsing and purchasing options. 
  • For developing efficient stock marketing platforms. 
  • For developing innovative social networking sites. 
  • For creating non-standard complex projects. 
  • Create SaaS solutions. 

Examples of famous applications built on Ruby are-  

  • GitHub 
  • Shopify 
  • Ask.fm 
  • Kickstarter 
  • Lnstacart 
  • Scribd 
  • ConvertKit 
  • Twitch 
  • Zendesk 
  • SoundCloud. 

A staple in Ruby and Rails interview questions, be prepared to answer this one. ORM is the short form for the Object Relational Model that helps connect an application's objects to tables within a relational database management system. It lets you store and access the properties and relationships of the application’s objects from a database without running the SQL statements directly.  

ORM is a library that encapsulates the code for manipulating the data without needing (SQL) anymore but uses an object of your language. 

  • You can use the Object with your programming language. 
  • The Relational specifies the Relational Database Manager System. 
  • And the Mapping will bridge your objects and your tables.

False and nil are the built-in data types in Ruby. Both are different and has different meaning.

Nil
FALSE

nil is a NilClass object 

false is a FalseClass object, 

not a valid value 

is a valid value 

does have a type 

is a boolean data type 

Both are different and have a different purposes in ruby on rails. Considering syntactically, strings are the text that is enclosed within the quotation marks, while the symbol is the text that starts with a colon sign.

Ruby symbols are “scalar value objects that you can use as identifiers, mapping immutable strings to fixed internal values.” Symbols are immutable strings that you cannot change.

Symbols are approx 1.7 times faster than Strings. If you use the same symbol multiple times, they will have the same object ID, referring to the same object. While, Strings will be a different object with a unique object ID, referring to different objects.

Rails controller is the logical part of the application. It orchestrates the user's interaction with the views and the model. There are other significant roles of the controller- 

  • It redirects external requests to the internal processes. 
  • It also controls the caching to improve the application's performance. 
  • It also controls the helper module for adding functionality to view the templates without adding code. 
  • It lets you track the session and interaction of the users with the app. 
  • To create the controller, you can use the following command.

C:\ruby\library> ruby script/generate controller Subject. 

Notice that we have capitalized the Subject and used the singular form. This command accomplishes several relevant tasks: 

It will create the file called app/controllers/subject_controller.rb, witht he following content 

class SubjectController < ApplicationController 

end 

The Controller classes inherit from ApplicationController, which is available in the other file in the controller's folder, called application.rb. 

A rails migration is a tool that allows you to alter the application’s database schema. Instead of using SQL scripts, you can use domain-specific language to define the database's modifications. As the code in RoR is database-agnostic, you can easily port the project to another platform. You can roll back and manage the modifications alongside your application source code.

We can use the following command to create a migration. 

For this, we can use the rails generates command in the rails command prompt. 

Go to start>>Railsinstaller>>command prompt, then root your application directory. 

Use the following code. 

Rails generate migration record1.

The migration file will convert to camel Case to underscore: record_1.rb with the current date and time, as shown. 

The file will be stored in the db directory inside migrate, and that file has a Ruby class defined in it. 

This is a frequently asked question in Ruby on Rails basic interview questions. Whenever we create an object, memory is allocated to it. Ruby supports two different types of memory. The first is the malloc heap, where the entire program is included. This memory will be released back to the operating system if the memory is known to be unused by Ruby at the end of a garbage collection.

The second is the Ruby object heap, a subset of the malloc heap that holds the most Ruby objects. If objects are large, they point to the malloc heap. The Ruby heap is consistently monitored and cleaned by the Ruby garbage collector.

Ruby works on the mark and sweep garbage collection algorithm that uses three colors. That marks every object with either white, black, or gray, hence the name tricolor

Each variable in Ruby is declared by placing a special character at the start of the variable name. Variables store some values that can be accessed and used within the program based on their scope.

Below are different types of variables available in Ruby. 

Local variables- these are the local variables we can use within the code block where they are declared. We use symbol [a-z] or _ 

For example- 

pi = 3.1415 
def valueofpi 
    pi = 3.142 
    puts "Value of pi inside valueofpi = #{pi}" 
end 
valueofpi() 
puts "Value of pi = #{pi}"

Instance variables- these variables are like Class variables whose values are local to specific instances of an object. We can use the instance variables across methods for any specified instance or object i.e., and instance variables can change from object to object. We use the symbol @. 

For example- 

class Employee 
    def set_data(empName, empAge) 
        @name = empName 
        @age  = empAge 
    end 
 
    def get_name() 
        return @name 
    end 
 
    def get_age() 
        return @age 
    end 
end 
 
e1 = Employee.new 
e1.set_data("rita", 24) 
e2 = Employee.new 
e2.set_data("sita", 31) 
puts "Employee #1, Name = #{e1.get_name()}, Age = #{e1.get_age()}" 
puts "Employee #2, Name = #{e2.get_name()}, Age = #{e2.get_age()}"

Class variables- these variables starts with @@ sign that are available across different objects. A class variable belongs to the class, and it is a characteristic of a class. They are also known as the global variables within the context of a single class. 

For example- 

@@no_of_customers = 0 

Global variables- always starts with $. Its scope is global, which means we can access it from anywhere in a program.

For example- 

$message = "hello" 
def changeMessage 
    $message = "heh" 
    puts "msg change #{$message}" 
end 
puts "changed msg #{$message}" 
changeMessage() 

Load reads and parses files every time during file execution. However, in most cases, developers use the “require” method. But there are some scenarios where we want to use the “load” to pick the latest module changes within the class 

Below is the syntax- 

load 'filename'

Require is used to read the file from the file system, parse it, save it to the memory, and run it in each place. If you make any changes to the file while the script is running, the “require” will not pick the changes as Ruby will use the file from th memory. 

Below is the syntax- 

require 'filename' 

MVC is the framework that divides any extensive application into three parts.

  • The Model- stores the data-related logic that seamlessly works with schemas and interfaces of a project, the databases, and their fields.
  • The View- specifies the UI and presentation of that application.
  • The Controller- it keeps the business-related logic for handling incoming requests.  
  • Each component is designed to handle a specific aspect of that application having different purposes.

Working of MVC- 

  • The browser sends a request to the Controller.  
  • The Controller communicates with the Model for sending and receiving the data. 
  • The controller then interacts with the View to render the data. 
  • The View then sends the final presentation to the Controller, and the Controller sends it to the user output.

Access modifiers are an important concept of the object-oriented programming language that restricts the visibility of methods and member fields to protect against accidental changes to the code. Regarding access control, Ruby is different from other Object Oriented Programming languages.

  • The visibility of the class variable and instance is always private. 
  • Access controls are only applicable to methods. 
  • We cannot apply access control to the instance and the class variables. 
  • We can inherit the private methods in Ruby as public and protected methods. 

We have 3 different access modifiers in Ruby, namely -  

  • Public: such members are available to everyone to make changes. by default, all the methods are public. 
  • Private: only methods within the class can access members. They are not accessible outside the class. We use the private keyword to define it.  
  • Protected: These methods' access is limited between the defined class and its subclass. We cannot access protected methods outside the defined class or its subclass.  

Ruby offers a program called ERB, which stands for Embedded Ruby. It is used when you need to directly put the codes associated with Ruby into the HTML files, irrespective of the size and complexity of the codes.

Editors are used to writing code. Ruby supports the usage of various editors. We can choose any editor as per our requirements and with ease.

  • NetBeans  
  • Eclipse  
  • Heroku  
  • Aptana Studio 
  • Komodo  
  • Redcar  
  • Arcadia  
  • Ice Coder 
  • TextMate 
  •  

The active records represent the “M” of the MVC, which is the system layer responsible for representing the business data and logic. It lets you access, create, read, update, and delete the data from the relational database. It is a core part of the MVC design.

Basic functionalities of the active record are- 

  • Establishing a connection with the database. 
  • Creating any number of tables in the database. 
  • Specifying the relationships between tables and classes. 
  • Performing CRUD operations. 
  • Creating object-relational mapping between classes, objects, rows, tables, etc. 

Gems are used to extend the functionalities of their distributions. Some gems get automatically installed with Ruby installation, while you need to install some explicitly. Also, you can have different versions of the same gems installed in your system.

Execute the following command to get the list of all the gems available.

rvm gemset list

RVM is a command-line tool that allows us to easily install, manage, and work with different ruby environments, from interpreters to sets of gems. The GitHub community maintains RVM through pull requests sent to the project repository. It lets us deploy each project with its own self-contained and dedicated environment.

  • It reduces the complexity of the many facets of ruby development through its command-line API.
  • It enables us to test both upgrade and escape paths quickly and consistently.
  • It offers a flexible gem management system called Named Gem Sets.

Below is the basic RVM syntax- 

rvm command_options command ruby_to_act_on.  

For upgrading the RVM, we use the following command. 

rvm get head   

Rails bundler offers a constant environment for applications by tracking required gems.

You can use the following command to use the specific bundler.

Gem install bundler. The gem bundler bundles all the suitable gems required by any specific application to work efficiently. Bundling Rails and other dependencies might increase the size by a few megabytes.

Fixtures allow you to organize data that you want to test against and can feed into your unit testing. The fixtures will be created automatically when rails generate any test for the controllers and models. They are just for test purposes, and you cannot access them while running the application.  

Typically fixtures are expressed in terms of YAML files. 

For example- 

# orders.yml 
payments_equal_line_item_total: 
  # no attributes needed 
# line_items.yml 
electric_polisher: 
  order: payments_equal_line_item_total 
  name: 'Electric polisher' 
  price_cents: 400 

Each YAML fixture is given a name and is followed by an indented list of key/value pairs in the “key: value” format. A blank line separates records for your viewing pleasure. 

The differences below will help you understand where to use strings and symbols. 

If the text available is “data,” then use a string. But, if it is code, then use a symbol. 

Symbols are not text; they are unique identifiers and are static, such as numbers, bar codes, etc., while, unlike symbols, strings be easily changed.  

You can use strings containing the exact text within the code multiple times by creating a new string object. While, for using the symbol, the number of times you do put, it will only create one object and can be reused. 

For example- 

# Symbols (same id) 
:foo_bar.object_id # => 2386588 
:foo_bar.object_id # => 2386588 
# Strings (different ids) 
"foo_bar".object_id # => 1020 
"foo_bar".object_id # => 1040 

You can use destroy to delete the record from the rails along with all dependencies. For example, the authors or other details associated with the book will all be deleted if you want to delete a book record.

For example- 

$ rails console 
Loading development environment (Rails 3.2.9) 
>> book = Book.create(title: 'example) 
    (0.1ms)  begin transaction 
  SQL (25.8ms)  INSERT INTO "books" ("created_at", "title", "updated_at") VALUES (?, ?, ?)  [["created_at", Sun, 18 Nov 2012 15:11:41 UTC +00:00], ["title", "example"], ["updated_at", Sun, 18 Nov 2012 15:11:41 UTC +00:00]] 
   (2.1ms)  commit transaction 
=> #
>> Book.count 
   (0.3ms)  SELECT COUNT(*) FROM "books"  
=> 1 
>> book.destroy 
   (0.1ms)  begin transaction 
  Author Load (0.1ms)  SELECT "authors".* FROM "authors" WHERE "authors"."book_id" = 1 
  SQL (0.3ms)  DELETE FROM "books" WHERE "books"."id" = ?  [["id", 1]] 
   (3.0ms)  commit transaction 
=> # 
>> Book.count 
   (0.2ms)  SELECT COUNT(*) FROM "books"  
=> 0 
>> 

Objects are the core building blocks of any OOP program. The same goes with Ruby on rails. An object is a combination of data and methods used to communicate through methods. Each object can receive messages, send messages, and process data. 

For creating an object. We must define a class, a template for an object describing the state and behavior that the class objects all share. We can create many objects for a class. Objects created at runtime from a class are called instances of that class. 

For example- 

#!/usr/bin/ruby 
class Being
end 
b = Being.new //object creation 
puts b 

In ruby, “==” returns true if the two comparison entities are the same. For example, if a=1.

At the same time, “equal” will check if both entities are the same object. For example- a.equal?(b) iff a is the same object as b

These are nonexecutable parts of a program. We can write comments in between our programs for reference purposes. We can write on one line or span multiple lines of comments. 

One-liner comment 

# one-liner 

Multiple line comments 

=begin 
Hello 
This 
Is 

Multi line comment 

=end 

Intermediate

Rake is a commonly used task management and build automation tool, allowing users to specify tasks and their related dependencies and group tasks in a namespace. You can also say that rake is the task runner that manages tasks like creating database backup, running tests, and gathering necessary reports. Without a rake, all the tasks will be scattered for all projects. It helps in accessing the tasks centrally. 

When we must run the rake task, we must ensure the following.

  • Check if the 'rake' gem is installed in the project SDK.
  • Check that the Rakefile is in the project's root.

RubyMine allows running an arbitrary Rake task. For example, we will see how we can run the db:migrate task for migrating a database in the Rails application.

Run a task using Run Anything.

Press ^ twice and type db:migrate in the invoked popup. Select rake db:migrate from the list and press enter.

Go to the main menu, select Tools | Run Rake Task ⌥ R. type g db:migrate in the popup, select db:migrate, and press enter.

Select the required migration version and the environment from the popup. Click OK. 

Run a rake text from the editor 

Open *.rake file. Click the Run Rake Task button on the gutter next to the required task or Place the caret at the required task name and press. ⌥ ⏎ 

Take the required action whether to run or debug the task, select Run '<task name>' or Debug '<task name>'. Press enter.

After the task is executed, RubyMine automatically creates a unique profile - a temporary run/debug configuration where we can customize the settings of this configuration.

It's no surprise that this one pops up often in interview questions about Ruby on Rails. You can use the destructive method to alter the state of an object. String, Array, Hash, and others have such methods. The method has two different versions, one with a plain name, the other with the same name, followed by !. The plain version will create a copy of the receiver, make the required change, and return the copy. The other or the “bang” version (with the !) alters the receiver in place.

Rails filters are methods that run either before or after the execution of the controller's action method. You can use this filter method when you want to ensure that a given code block runs with a specified action method called. 

There are three filter methods: 

Before filters- Rails before filters are executed before the code in the action controller. They are defined at the top of a controller class that calls them. To set it up, you need to call the before_filter method.

For example- 

class UserController < ApplicationController    
before_filter :verify_password   
def verify_password   
...    
end    
end   

After filters- these filters are executed after the code in action controller executes. Just like before filters, after filters are also defined at the top of a controller class that calls them. We need to use the after_filter method to set it up. 

For example- 

class PhotoController < ApplicationController    
after_filter :resize_photo    
def resize_photo    
...    
end    
end  

Around filters- Rails around filters contain codes that can execute both before and after the execution of the controller's code. They are used when you need both before and after the filter. Implementing around filters is more complex than the other two filters. It is defined by a common class containing both before and after methods.

For example- 

class ActionLogger    
def before(controller)    
@start_time = Time.new    
end    
def after(controller)    
@end_time = Time.now    
@elapsed_time = @end_time.to_f - @start_time.to_f    
@action = controller.action_name    
table    
end    
end   

Observers are the simple method, allowing one object to inform a set of objects when its State changes. It is used when a one-to-many relationship exists between the object. If one object gets a notification, another dependent object will also get a notification and update automatically.

Execute the following command to create an observer. 

$ rails g observer User 

We will explain this with a simple example where we would like to send emails to the user based on their activity status. 

class User < Activerecord::Base 
  after_save :send_email 
  private 
  def send_email 
    if status_changed? 
      UserNotificationMailer.account_open_email(self).deliver if status=='created' 
      UserNotificationMailer.account_activated_email(self).deliver if status == 'active' 
      UserNotificationMailer.account_deactivation_email(self).deliver if status =='deactive' 
    end 
  end 
End 

The above code works fine as expected. But there is some issue. Yes, our model job is not to send emails. It will violate the Single Responsibility Principle. So better to implement the observer pattern here.

We will now create a UserObserver class inside the model, which will inherit from ActiveRecord::Observer. 

class UserObserver < ActiveRecord::Observer 
  def after_save(record) 
    if record.status_changed? 
      UserNotificationMailer.account_open_email(record).deliver if record.status=='created' 
      UserNotificationMailer.account_activated_email(record).deliver if record.status == 'active' 
      UserNotificationMailer.account_deactivation_email(record).deliver if record.status =='deactive' 
    end 
  end 
end 

Callbacks are commonly used within an object’s life cycle at certain moments, such as after a state change. While using callbacks, you can write codes while creating, saving, updating, deleting, loading, or validating the active record object from the database.

It will give you greater control of data and the applications using it. It changes the usual flow of the code, resulting in complicated debugging and test-making. 

There are three types of callbacks.  

  • before_create – these run before the stated object. 
  • after_create – these run after the stated object. 
  • around_create – allows you to have code before and after the original action, where you decide when the original action gets done.

For using a callback, we need to “register” it at the top of your Model using method  specifying the type, such as before_create. We can either pass that method a symbol that corresponds to the method name or write the callback as a block at once. 

For example 

class User < ActiveRecord::Base 
  before_create do |user| 
    puts "Creating #{user.name}" 
  end 
    after_create :Created 
    private 
  def just_created 
    puts "User Created." 
  end 
End 

In this example, we create a class linked with the database. We call the before_create to check some requirements. Then, call the after_create, which displays the message. 

The harness lets you view high-level application metrics collected from various sources and forward them to the collector. You can use any collector that can simply implement the Statsd interface. The harness takes the metrics from ActiveSupport::Notifications and forwards them to the collector.

The harness automatically assumes that the collector can do proper metric aggregation and statistics. For example, using the statsd will calculate the 70th percentile and averages.

You can use a harness specially for very high-traffic applications. Each metric is processed in a separate thread, where the main thread will do just sufficient work.

A symbol is mostly confused with variables, but both are different. Symbols are written like this: “:something,” preceded by a colon. Typical symbols do not contain spaces. So, if you want to create a symbol with multiple words, you need to use underscores, like so: :another_funny_symbol.

//add use cases// 

A Proc object encapsulates the code block you can store within a local variable, pass to a method or another Proc, and be called.  

For example 

square = Proc.new {|x| x**2 } 
square.call(3)  #=> 9 
# shorthands: 
square.(3)      #=> 9 
square[3]       #=> 9 

Proc objects are closures, meaning they can remember and use the entire context in which they were created. 

def gen_times(factor) 
  Proc.new {|n| n*factor } # remembers the value of factor now of creation 
end  
times3 = gen_times(3) 
times5 = gen_times(5) 
times3.call(12)               #=> 36 
times5.call(5)                #=> 25 
times3.call(times5.call(4))   #=> 60 

count() is an Array class method that returns the total number of elements present within the array. Count uses three different approaches. 

Count all: do not require any parameter and will return a count of all the rows. 

For example 

Person.count         # returns the total count of all people 

Count using column: pass a column name to count and will return a count of all the rows for that column present. 

For example- 

Person.count(:age)  # returns the total count of all people whose age is present in the database 

Count using options will find the row count based on the options. 

For example- 

Person.count(:conditions => "age > 26") 
  Person.count(:conditions => "age > 26 AND job.salary > 60000", :include => :job) # because of the named association, it finds the DISTINCT count using LEFT OUTER JOIN. 
  Person.count(:conditions => "age > 26 AND job.salary > 60000", :joins => "LEFT JOIN jobs on jobs.person_id = person.id") # finds the number of rows matching the conditions and joins. 
  Person.count('id', :conditions => "age > 26") # Performs a COUNT(id) 
  Person.count(:all, :conditions => "age > 26") # Performs a COUNT(*) (:all is an alias for '*') 

The size() is a method that is inbuilt into ruby. It returns the size of the set. Simply put, it will return the number of elements present in the set. 

For example- 

require "set"  
s1 = Set[11,2,3,4,5] 
# size method used 
puts s1.size() 

This question is a frequently asked question in Ruby on Rails interview questions. Ruby offers a mechanism for handling exceptions effectively. We need to enclose the code raising or throwing an exception in a begin/end block and use rescue clauses to tell Ruby the types of exceptions we want to handle.

Below is the syntax for exception handling in Ruby 

Syntax 

begin   
# -   
rescue OneTypeOfException   
# -   
rescue AnotherTypeOfException   
# -   
else   
# Other exceptions 
ensure 
# Always will be executed 
End 

The code within the begin/rescue block is protected. If any error occurs while executing this block, the control will pass to the block between the rescue and end.

For each rescue block, ruby will compare the raised exception for the match and parameters. If the exception name and the name in the rescue parameter are the same, then the block will execute, and the output will be displayed. 

For example- 

#!/usr/bin/ruby 
begin 
   file = open("/unexistant_file") 
   if file 
      puts "file is open" 
   end 
rescue 
      file = STDIN 
end 
print file, "==", STDIN, "\n" 

You will get below output- 

#<IO:0xb7d16f84>==#<IO:0xb7d16f84> 

Initializers are class instance members that get called whenever a class’s object is created. We must use the name initialize for Initializer. 

For example, for an Employee class, we must have an instance method by the name initialize. 

Ruby supports two types of initializers. 

Parameterless initializer 
Parameterized initializer 
For example- parameterless initializer 
class Employee 
    def initialize 
        @employeeId = 1 
        @employeeName = "sita" 
    end 
 
    def setEmployeeId(empId) 
        @employeeId = empId 
    end 
 
    def setEmployeeName(empName) 
        @employeeName = empName 
    end 
 
    def getEmployeeId 
        return @employeeId 
    end 
 
    def getEmployeeName 
        return @employeeName 
    end 
end 

We can use this initializer when we want to set some default values for employee objects. Now create employee object as shown below. 

employee1 = Employee.new 
puts "Employee ID is #{employee1.getEmployeeId()}" 
puts "Employee Name is #{employee1.getEmployeeName()}" 

For example- parameterized initializer 

class Employee 
    def initialize(empId, empName) 
        @employeeId   = empId 
        @employeeName = empName 
    end 
    def setEmployeeId(empId) 
        @employeeId = empId 
    end 
    def setEmployeeName(empName) 
        @employeeName = empName 
    end 
 
    def getEmployeeId 
        return @employeeId 
    end 
 
    def getEmployeeName 
        return @employeeName 
    end 
end 

We can use this initializer when we want to set values for employee attributes while creating the object. Here, we have a parameterized constructor for the Employee class accepting ID and name and assigning it to the Employee object. 

Now, create an employee object with parameters as shown below. 

employee1 = Employee.new(23, "abc") 
puts "Employee ID is #{employee1.getEmployeeId()}" 
puts "Employee Name is #{employee1.getEmployeeName()}" 

Functions are a combination of procedural statements that uses functions to execute specific code. For example, a function to perform addition need to declare two variables and add them. A function can return a value to the method that calls that function. If a function does not return a value to the caller, the value is None. 

For example- 

def add() 
a = 10 
b = 20 
return a + b 
end 
print add() 

Scaffolding refers to the auto-generation of a simple set of a model, views, and controllers, usually for a single table.

Two types of scaffolding are available in Ruby- static and dynamic.

Below is the basic difference between static and dynamic scaffolding.

Dynamic Scaffolding
Static Scaffolding 

It generates all content and user interface at runtime. 

We need to provide an explicit entry in the command to generate the data with their fields. 

We can create new, delete, and modify methods for usage in your application. 

Such a generation does not need to occur. 

Synchronization is not necessary with a database. 

It necessitates the migration of the database. 

No doubt, Ruby applications are highly scalable. The significant reasons are: horizontal scaling and is thread-safe. In other words, it will help your application handle more traffic by providing support for additional Ruby processes and adding additional servers.

The Rails console is a command line utility running the Rails applications from the command line, an extension of Ruby IRB. It offers all the facilities of IRB and the ability to auto-load the Rails application environment, including all its classes and components.

Advanced

A must-know for anyone heading into a Ruby on Rails interview, this question is frequently asked in Ruby Interview Questions. Active Job is a framework to declare and run the jobs on different queueing backends. You can use any job, from regularly scheduled clean-ups to billing charges to sending emails. It is suitable for those tasks that you can split into several small tasks that can be executed simultaneously.

The strong parameters provide an interface that protects the attributes from the end-user assignment. In this case, the Active model does not use the Action Controller parameters for mass assignment until they are explicitly enumerated. 

Also, you can mark the parameters as required and flow through a predefined flow to end up as a 400 Bad Request without effort.

Different naming conventions exist for variables, constants, methods, parameters, classes, models, controllers, and modules. 

  • Local variables 

example = 0 

example_variable = 0 

  • Instance variables 

@example 

  • Class variables 

@@example 

  • Global variables 

$example

  • CONSTANTS 

EXAMPLE_CONSTANT

  • Methods  

def example 

End

  • Parameters

def some_method (example) 

end

  • Classes 

ClassExample

  • Models 

Example

  • Controllers 

ExamplesControler

  • Modules 

ModuleExample 

Inheritance allows a class to inherit the attributes and behavior of another class. The class that inherits is called the subclass or the child class, and the inherited class is called the superclass or parent class.

Inheritance uses the syntax Subclass < Superclass. If you have C < A, then class C is a child class of A, C inherits from A, or A is the parent of C.

For example,  

class Exam  
    def initialize 
                puts "Superclass" 
    end     
    def super_method       
       puts "Method of superclass" 
    end 
end
class Sudo_Placement < Exam 
    def initialize 
       puts "Subclass" 
    end 
end 
Exam.new 
sub_obj = Sudo_Placement.new 
 sub_obj.super_method 

Finders in rails help you find specific records with or without any mentioned conditions.  

For example- 

To find an author with id 50 

Author.find(50) 

To find authors with id- 20, 30, 40. 

author.find([20, 30, 40]) 

To find the author with the first name as “sita.” 

Author.find :all 
            :condition => ["first_name =?", "sita" ] 

Available options to be used for finders- :order, :offset, :limit, :group, :joins, :include, :select,: readonly.

If you want to make your application ready for multiple databases, then you need to do that explicitly. Suppose we have an application with a single writer database, and we want to add a new one. Then you must make changes to the database.yml file.

Existing database.yml
production: 
  database: my_prim_database 
  adapter: mysql2 
  username: root 
  password: <%= ENV['ROOT_PASSWORD'] %> 

First, add a replica for the existing configuration, and a second database called pet and a replica for that. 

New database.yml

production: 
  primary: 
    database: my_prim_database 
    username: root 
    password: <%= ENV['ROOT_PASSWORD'] %> 
    adapter: mysql2 
  primary_replica: 
    database: my_prim_database 
    username: root_readonly 
    password: <%= ENV['ROOT_READONLY_PASSWORD'] %> 
    adapter: mysql2 
    replica: true 
  animals: 
    database: my_pet_database 
    username: pet_root 
    password: <%= ENV['PET_ROOT_PASSWORD'] %> 
    adapter: mysql2 
    migrations_paths: db/pet_migrate 
  animals_replica: 
    database: my_pet_database 
    username: pet_readonly 
    password: <%= ENV['PET_READONLY_PASSWORD'] %> 
    adapter: mysql2 
    replica: true 

Note 

  • The the primary and primary_replica name should be the same containing the same data. 
  • You should use different usernames for the writers and replicas. 
  • The replica database should have readonly access. 
  • For using the replica database, add a replica: true entry to the replica in the database.yml. 
  • If you create a new writer database, set the migrations_paths to the directory where you store migrations for that database.

Rails::Engine lets you wrap a specific Rails application or a subset of functionality to share it with other applications or within a more extensive packaged application. Every Rails::Application is just an engine allowing simple features and application sharing. 

//Add code examples// 

It offers you a framework that compresses JavaScript and CSS assets. You can use it to write these assets in other languages and pre-processors such as CoffeeScript, Sass, and ERB. Using this, you can automatically combine your assets with assets from other gems.

You can implement the asset pipeline using the sprockets-rails gem enabled by default. To disable it while creating a new application, you must pass the --skip-asset-pipeline option.

One of the most frequently posed Ruby interview questions, be ready for it.  The closure is a function or a code block with variables bound to the environment from which the closure is called. The closure is used as a variable that you can assign to another variable or pass to any function as an argument.

You can define a closure block in one scope and call it in a different scope.

Closure can recognize the variable available within its scope at the creation time and, while calling it, can access the variable even if they are not in the current scope.

Examples of closure in ruby are- Blocks, procs, and lambda.

Blocks are the simplest form of closure, a code piece enclosed between braces {} or do…end. 

You can pass more than one variable to the block. 

You can use a yield statement to call a block within a method with a value. 

It does not have a specific name. 

Below is the syntax for creating a block. 

block_name { #statements_to_be_executed } 
Using do…end 
block_name do  
   #statement-1   
   #statement-2   . 
End 

For example-

arr = [10, 11, 13, 41, 59] 
arr.each do | item | 
puts item 
End 

The forEach() method allows you to loop through each element of an array/object. The forEach() method takes a callback function as an argument invoked for each array element. It is like the for loop but without a return value.

The map() method loops through each element of an array/object. The map() method takes a callback function as an argument that is invoked for each array element. It is like the forEach() method but returns a new array.

Below is the syntax for the map. 

array = ["a", "b", "c"] 

array.map { |string| string.upcase } 

# ["A", "B", "C"] 

First, we will have an array. It could be a hash or range. Then we will call a map with a block. It will return a new array with the results. The result will not change, but you can use the map to change the original array. 

For example- 

Doubling the numbers of an array. 

array = [1,2,3] 

array.map { |n| n * 2 } 

# [2, 4, 6] 

Converting string to numbers. 

array = ["11", "21", "5"] 

array.map { |str| str.to_i } 

# [11, 21, 5] 

Indexing values with the “with_index” method. 

array = %w(a b c) 

array.map.with_index { |ch, idx| [ch, idx] } 

# [["a", 0], ["b", 1], ["c", 2]] 

Lambdas are procs that have distinguishing factors. They are considered the “regular” methods in two ways: they enforce the number of arguments that need to be passed when called, and they use "normal" returns. 

When calling a lambda that expects an argument without one, or if you pass an argument to a lambda that does not expect it, an ArgumentError. Will be raised. 

irb> lambda (a) { a }.call 
ArgumentError: wrong number of arguments (given 0, expected 1) 
        from (irb):8:in `block in irb_binding' 
        from (irb):8 
        from /Users/jeff/.asdf/installs/ruby/2.3.0/bin/irb:11:in `<main>' 

Also, for a lambda, the return keyword is same as it is for a method. When calling a proc, the program yields control of the code block. So, if the proc returns, the current scope returns. If a proc is called inside a function and calls return, the function immediately returns. 

def return_from_proc 
  a = Proc.new { return 10 }.call 
  puts "not printed." 
end 

The above function will yield control to the proc, so when it returns, the function returns. Calling the function in this example will never print the output and return 10. So we use lambda. 

def return_from_lambda 
  a = lambda { return 20 }.call 
  puts "The lambda returned #{a}, and this will be printed." 
End 

When using a lambda, it will be printed. Calling return in the lambda is like calling return in a method, so the “a” variable is populated with “20,” and the line is printed to the console. 

With hashes, we can store data as key-value pairs. You can retrieve and modify data using the key. 

For example- 

countryCapitals = {} 
countryCapitals["India"] = "Delhi" 
countryCapitals["United States"] = "D.C." 
countryCapitals["United Kingdom"] = "London" 
puts "Count is = #{countryCapitals.length}" 
# Using Subscript to query the dictionary for a key and get the value. 
puts "Capital of India is = #{countryCapitals['India']}" 
# iterate the hash using each 
countryCapitals.each do |key, value| 
    puts "#{key} => #{value}" 
end  
#  if the hash contains NYC as a key. 
puts "ContainsKey - NYC?: #{countryCapitals.key?("NYC")}" 
# if the dictionary contains London as a value. 
puts "ContainsValue - D.C.?: #{countryCapitals.has_value?("London")}"
# remove an entry from the dictionary. 
countryCapitals.delete("India") 
# Print the hash 

puts countryCapitals

Computer systems are connected via networks. Two commonly used protocols in a network. 

TCP - Transmission Control Protocol. 

UDP - User Datagram Protocol. 

Network protocol implementations for TCP come under the TCPSocket class. TCP protocol provides same-order communication, which is useful for other protocols like HTTP, SecureFTP, etc. 

UDP on the other hand, sends independent datagrams. So there is no specific order in which data is received. UDP is connectionless. 

A network computer is identified with two parameters. 

IP Address 

Port- 16-bit numbers that can range from 0 to 65,535. 

Let us create a sample client-server program in Ruby to understand basic networking APIs. 

Server- 

require 'socket' 
cosmic_server = TCPServer.open(8080) 
loop { 
    cosmic_client = cosmic_server.accept 
    cosmic_client.puts "Hello There. I am Cosmic Server" 
    cosmic_client.close 
} 

Client- 

require 'socket' 
cosmic_server = TCPServer.open('localhost', 8080) 
while data = cosmic_server.gets 
    puts data 
end 
cosmic_server.close 

The Client receives the message from the local IP address and port 8080. 

Serialization is the process that writes an object's data to a stream. 

The inverse process of reading the stream into an object is called Deserialization. This concept is useful when you want to preserve and retrieve the object’s state later

  • Serialization is implemented via a class called Marshal. The methods in Marshal that help with Serialization are- 
  • Marshal.load- which Read data from the Input stream into an Object. 
  • Marshal.dump-that Write data from the Object into the Output stream.  

For example- (serialization) 

class Employee 
    def initialize(empId, empName) 
        @empId = empId 
        @empName = empName 
    end 
 
    def get_empId 
        return @empId 
    end 
 
    def get_empName 
        return @empName 
    end 
end 
 
emp = Employee.new(1, "sita") 
seredObject = Marshal.dump(emp) 

The above example has created an Employee class. In this example, we have used the Marshal.dump to serialize the Employee to a binary object. 

For example- (deserialization) 

class Employee 
    def initialize(empId, empName) 
        @empId = empId 
        @empName = empName 
    end 
 
    def get_empId 
        return @empId 
    end 
 
    def get_empName 
        return @empName 
    end 
end 
 
emp = Employee.new(1, "sita") 
seredObject = Marshal.dump(emp) 
 
emp2 = Marshal.load(seredObject) 
puts "Employee ID = #{emp2.get_empId}" 
puts "Employee Name = #{emp2.get_empName}"

Ruby allows us to open a file using the File module in different modes- read mode, write mode, append mode, etc. we will explain this with an example of how we can open a file for reading. 

For example- (reading) 

newFile = File.new("C:/Desktop/new.txt", "r") 
while ( line = newFile.gets) 
    puts line 
end 
newFile.close() 

In the above example, we have opened the file and printing the output using “puts.” 

For example- (writing). 

newFile = File.new("C:/Desktop/godzilla2.txt", "w") 
newFile.write("hello") 
newFile.write("Hii") 
newFile.close() 

In the above example, after writing to the file, we have close it using the “close()” function.

Ruby allows us to create and work with threads with the concept of multithreading. It lets us create several threads, that run in parallel and share process CPU and memory. Multiple threads can share memory and communicate with each other. This can significantly speed up your program execution. 

Suppose, we need to parse a large CSV file, for that, we can create as many worker threads to do it and speed up time. Also, if we want to run the task as a background operations in a User Interface program, we can create a background thread to do so. 

For example- (creating a thread) 

def run 
    puts "running thread" 
end 
t1 = Thread. new{run()} 
T1.join 

For example- (joining a thread) 

def cosmicthread1 
    puts "hello?" 
    puts "working" 
end 
def cosmicthread2 
    puts "hello2" 
    puts "I = got it?" 
end 
def cosmicthread3 
    puts "Human Knowledge belongs to the World" 
    puts "Like Asprin" 
end 
cthread1 = Thread.new{cosmicthread1()} 
cthread2 = Thread.new{cosmicthread2()} 
cthread3 = Thread.new{cosmicthread3()} 
cthread1.join() 
cthread2.join() 
cthread3.join() 

Using I/O capabilities, we can provide input and get output from the program. Ruby provides API functions, such as gets and puts to work with console input and output.  

For example- puts function. 

str = "shortcut" 
puts str 
j = 10 
puts "The value of j is #{j}" 

For example- gets function 

puts "enter name:- " 
name = gets 
puts "Hello #{name}" 

def scrub_string str 
  str = str.to_s if !str.is_a?String 
  str = str.gsub(/\W|\_/, "").downcase 
end 
 
def check_palindrome? str 
  str = scrub_string(str) 
  (str.length/2).times do |index_counter| 
    if str[index_counter] != str[-(index_counter + 1)] 
      return false 
    end 
  end 
  true 
end 
 
def check_palindrome? str 
  str = scrub_string(str) 
  str == str.reverse ? true : false 
end 
p check_palindrome?("a")  

class Human

    def talk 
        puts "I’m talking" 
    end 
     private 
     def whisper 
          puts "I’m whispering" 
     end 
end 

What is the output of 

  • h=Human.new.talk 
  • k=Human.new.send(:talk) 
  • l=Human.new.send(:whisper)

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
# one line version 
arr.each { |number| puts number } 
# multi-line version 
arr.each do |number| 
  puts number 
end 

  • Get the value of key `:b`. 
  • Add to this hash the key:value pair `{e:5}` 
  • Remove all key:value pairs whose value is less than 3.5 

  • puts "Ruby Version: "+RUBY_VERSION 
  • puts "Ruby Patch Level: "+RUBY_PATCHLEVEL.to_s

  • require 'date' 
  • current_time = DateTime.now 
  • cdt = current_time.strftime "%d/%m/%Y %H:%M" 
  • puts "Current Date and Time: "+cdt 

def multiple_string(str, n) 
    return str*n 
end 
print multiple_string('a', 1),"\n" 
print multiple_string('a', 2),"\n" 
print multiple_string('a', 3),"\n" 
print multiple_string('a', 4),"\n" 
print multiple_string('a', 5),"\n" 

def start_if(str) 
   return str[0, 2] == "if"; 
end 
print start_if("ifelse"),"\n" 
print start_if("endif"),"\n"