header image

Ruby on Rails Popular Job Interview Questions

   Back to list

In each of our lives comes the stressful moment when we search for a satisfactory job. A key part of this search is the job interview, because it is an opportunity for the employer to check if we are qualified for the job. To do well on the interview, you should prepare yourself for it as much as you can. Good preparation will reduce your stress during the conversation, increase your self-confidence, improve your interview performance, and help your chances of getting your dream job.

One of the most important parts of interviewing for a Ruby on Rails Developer position is the technical part. In this section, the employer will check your knowledge of Rails, both technical and theoretical. In this article I will try to present popular questions that can appear in an interview for a Ruby on Rails Developer position. I will add also some useful tips which can help you during the interview.

So let’s start!

Set up sandbox app

For better understanding some questions will be explained on our sandbox app. I used 5.0.2 version of Rails and SQLite as a database. Let’s create it!

$ rails new sandbox
$ cd sandbox
$ bundle install
$ rails g scaffold Employee name:string phone:string department:references
$ rails g scaffold Department name:string
$ rake db:migrate

Above comments create a sandbox application and two models: Employee and Department, with the relation one-to-many (ie. one Department can have many Employees and one employee can have only one Department).

Now, let’s populate our database with sample data.

Please modify the db/seeds.rb file to look like this: seeds.rb

department_one = Department.create(name: 'Sales')

department_two = Department.create(name: 'Marketing')
Department.create(name: 'Financial')

Employee.create([{name: "Mike", phone: "111111111", department: department_one},
             	{name: "Nina", phone: "222222222", department: department_one},
             	{name: "John", phone: "333333333", department: department_one}
            	])
Employee.create(name: "Tom", phone: "111111111", department: department_two)

and after that, run:

$ rake db:seed

Ruby on Rails

In this section I will cover essential Ruby on Rails questions:

1. What is the difference between find() and find_by()?

Open the Rails console and type these commands.

ruby_rails_interview_questions_screen1

As you can see both find_by() and find() return the first record when its found.

Rails console

The difference is what they return when a record is not found.

find_by() returns nil while find() returns ActiveRecord::RecordNotFound exception.

The additional difference between find() and find_by() is that find could only be used to search by primary key (usually the ‘id’) while the find_by() requires and searches by attribute (either passed as hash like Employee.find_by(name: ‘Mike’) or using the Employee.find_by_name(‘Mike’) method).

2. What is the difference between member route and collection route?

Let’s edit config/routes.rb file.

Replace:

 resources :employees

with:

  resources :employees do
    member do
      get :preview
    end
    collection do
      get :search
    end
  end

Let’s see what routes it creates.

Run this command:

$ rake routes | grep employees

member route and collection route

A member route acts on a specific resource so it requires id, while a collection route acts on a collection of resources. Preview displays specific employee (a single object) when Search displays all employees (a collection of objects).

The rest of the eight routes are created by the resources keyword. A resourceful route provides a mapping between HTTP verbs and URLs and controller actions. All above routes are mapping to the Employees controller.

3. What is the N+1 query problem and how can one remove it?

First, in app/views/employees/index.html.erb file replace this piece of code:

<td><%= employee.department %></td>

with this:

<td><%= employee.department.name %></td>

Now, let’s start our app and go to http://localhost:3000/employees

In terminal you will see that our app sent 5 (4+1) queries to the database, 1 to fetch the 4 recent employees and then 4 for their corresponding departments.

N+1 query problem

In short words the N+1 problem is caused when you need to make N+1 SQL queries (where N is the number of items) to fetch the parent, then any number of child queries to fetch the other records. Every unnecessary query slows down our application, so it’s very important to solve this problem.

The solution to the N+1 problem is eager loading. This makes sure you don’t end up running unnecessary queries while looping through an object.

So how can you remove it? It’s really simple. In app/controllers/employees_controller.rb let’s replace this piece of code:

def index
  @employees = Employee.all
end

with this:

def index
  @employees = Employee.all.includes(:department)
end

Ok, now, let’s go again to http://localhost:3000/employees

You will see that this time, the app only sent 2 queries to the database.

eager loading

It’s because includes() method specify relationships to be included in the result set. That’s why the app calls database queries twice, only one query to get all employees and second query to get all departments of employees. So as you can see eager loading improves performance by cutting down the number of SQL queries.

Important: You have to be aware that eager loading might not be the solution for the N+1 problem in every case. Occasionally some complicated situations appear. For example, you can have a weird relations connection, in which eager loading won’t be solution.

4. Could you explain polymorphic associations?

Polymorphism is the provision of a single interface to entities of different types. With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you can have a comment model that belongs to either an employee model or a department model. Let’s see how we can implement it!

First we will need to create Comment model, because it will be the model which declares the polymorphic interface. It has to have both a foreign key column and a type column:

$ rails g model Comment description:string commentable_id:integer commentable_type:string
$ rake db:migrate

Next, we have to declare associations in models.

Add to the Department model and to the Employee model after the class declaration this piece of code:

has_many :comments, as: :commentable

And this piece of code to the Comment model:

belongs_to :commentable, polymorphic: true

After that, let’s reopen the Rails console and check out how polymorphic association works:

$ e = Employee.first
$ comments = e.comments.create([{description: "Employee of year"},{description: "Great guy!"}] )
$ comments.pluck(:description, :commentable_type)

polymorphic associations

As you can see in our above example, after creating two comments for the employee, the field commentable_type in comment model is automatically set for the association model name (i.e. Employee).

Now let’s create comment for department.

$ d = Department.first
$ comments = d.comments.create([{description: "My lovely department"}])
$ comments.pluck(:description, :commentable_type)

comment for department

You can see that if you create comment for department, the field commentable_type will be set with the value “Department”.

5. What’s the difference between redirect_to and render?

Render can be used in many ways, but it’s mainly used to render your html views. Calling render will create a full response that is sent back to the browser. For example add this line of code to the the show method in app/controllers/employees_controller.rb before the method end:

render "employees/edit"

Now go to: “http://localhost:3000/employees/1”

this will render the view “app/views/employees/edit.html.erb

redirect_to will send a redirect to the user’s browser telling it to re-request a new URL. Then the browser will send a new request to that URL. For example let’s replace:

render "employees/edit"

in show method in app/controllers/employees_controller.rb with:

redirect_to "https://www.nopio.com/"

After that go to “http://localhost:3000/employees/1”. You will be redirected to Nopio site.

6. Explain MVC pattern.

The Model View Controller principle divides the work of an application into three separate but closely cooperative subsystems:

  • Model – contains all business logic and data for the application
  • View – generates the user interface, which presents data to the user
  • Controller – is responsible for controlling the application logic and acts as the coordinator between the View and the Model

7. Explain request/response cycle.

Here is the request/response cycle:

request/response cycle

Let’s explain request/response flow in Rails:

  1. The user opens their browser and enters a URL.
  2. The browser sends a GET request to the URL. The request hits the Rails Router (config/routes.rb).
  3. The router receives the request information from the web server and based on that, decides which controller action should be called. If a request matches to any path in the routes file, the corresponding controller and action will be called.
  4. The controller receives the parameters from the router and passes them into appropriate model methods.
  5. The model queries a database to fetch data.
  6. The Database returns stored data to the model.
  7. The model manages the data and returns it to the controller.
  8. The controller feeds the received data to the view.
  9. The view renders the page as HTML, prepares a response and forwards it to the controller.
  10. The controller forwards the ready response to the browser.
  11. The browser displays a response to the user.

8. What are benefits of using Active Record as opposed to raw SQL queries?

Here are the benefits:

  • it’s really easy to go wrong during writing SQL queries
  • each different type of database usually has a slightly different flavour of SQL, so it could be really painful if, during work on a big app, you decide to switch to a different database
  • using Active Record reduces code significantly and makes it easier to read
  • using Active Record makes common operations simpler and easier than writing your own SQL statements

Let’s compare Active Record query with raw SQL query in an example. Let’s find all employees whose department name is ‘Sales’.

Using Active Record:

$ Employee.joins(:department).where(:departments => { name: "Sales" })

Using raw SQL:

$ Employee.find_by_sql("select employees.* from  employees inner join departments on departments.id = employees.department_id where departments.name = 'Sales'")

You can run these queries in the Rails console to check how they work.

9. What are the drawbacks of using Active Record and when we shouldn’t use it?

Although Active Record has many advantages over the raw sql queries, there are some situations when using plain sql queries is the better option. You should use raw sql queries instead of an Active Record query when you have to create a query with complex criterias, and when you have to update significant amount of records. In the first case raw sql query will be easier to write and less confusing. For the second case, let’s analyze this situation as an example.

Firstly, let’s add a larger amount of data into the Department table. Add to the db/seeds.rb file this piece of code:

(1..1000).each do |i|
  Department.create(name: 'Test')
end

And run:

$ rake db:seed

Now, let’s add  all of our employees to one department. First, let’s try this with Active Record.

Create migration:

$ rails generate migration AddDepartmentToEmployeesWithAR

Replace the update method in this migration with this piece of code:

def change
  Employee.all.each do |employee|
    employee.update(department_id: 1)
  end
end

Now, let’s do the same thing; but this time we will use raw sql query to update all employees with one department.

Create migration:

$ rails generate migration AddDepartmentToEmployeesWithSQL

Replace update method in this migration with this piece of code:

def change
  execute 'UPDATE employees SET department_id = 2'
end

Now let’s see which migration will be faster.

migration

As you can see, second migration which uses plain sql query is much faster than first migration which uses ActiveRecord query.

10. What are Active Record callbacks and which ones are you familiar with?

Callbacks are methods that get called at certain moments of an object’s life cycle. With callbacks it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database. Here are some example of callbacks:

  • before_validation
  • before_save
  • before_destroy
  • after_update
  • after_save
  • after_commit

Here is the link to all Active Record callbacks: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

Let’s see, for example, how before_save works. First add this piece of code to the app/models/employee.rb:

before_save :change_name

def change_name
  self.name = "Zeus"
end

Now restart the Rails console and run:

$ Employee.create(name: "Tom", phone: "111111111", department: Department.last)
$ Employee.last

As you see, we want to create an employee with the name “Tom”, but before we can save it, save callback call change_name method occurred which set the employee’s name as “Zeus”. That’s why Employee.last returns an employee with name “Zeus”.

11. What’s the difference between destroy and delete?

Both of these methods delete the record in the database. The different between them is that:

  • destroy – checks and deletes connected records if necessary and calls callbacks i.e. before_destroy, after_destroy etc.
  • delete – doesn’t call callbacks and removes an object directly from the database.

12. What’s different between ActiveRecord::Relation’s count, length and size methods?

  • count – counts the number of elements using query with the SQL command ‘COUNT’ but the result is not stored internally during object life cycle. This means, each time we invoke this method, SQL query is performed again. You should use this method if you don’t have anything loaded.
  • length – loads all objects just to count them and then return the result count. It should be used only if you have already loaded all entries to avoid another database query.
  • size – returns the size of the collection. If a collection is loaded, it will count its elements without any database query; but if a collection is not loaded, it will perform an additional query.

So we can say that size adapts to the situation.

13. What’s the difference between new, save and create?

  • new – makes a new object but doesn’t save it to the database
  • save – saves the model. If the model is new a record gets created in the database, otherwise the existing record gets updated.
  • create – makes a new object and saves it to the database in one go

14. What’s the difference between nil?, empty?, blank? and present? methods?

  • nil? – tests whether the object is exactly nil, that is whether it is an instance of NilClass
  • empty? – can be used on strings, arrays and hashes and returns true if they don’t contain elements. If called on something that is nil, it will throw a NoMethodError.
  • blank? – an object is blank if it’s false, empty, or a whitespace string.
  • present? – An object is present if it’s not blank.

Here is the table with all the cases:

nil?, empty?, blank? and present? methods?

Useful tips

Besides the preparation for the technical part, you should also think about and research a few important things:

  • What does the company do?
  • What kind of skills is the employer looking for?
  • What qualifications do you need for the position?

Furthermore, you should take care of your appearance and demonstrate a strong motivation to work. You should also prepare some questions of your own for the interviewer.

Conclusion

In this article I introduced some popular questions with Ruby on Rails which you might be asked during a job interview. I also included some useful tips which I hope will help you find your dream job as a software developer. I also recommend reading the article: Is software engineering hard? If you have any questions please put them in the comments. Also, if you want to share any interesting questions which you encountered on your interviews feel free to put them in the comment. I’d be happy to update this article to include them.

Good luck on the interview. Let us know how it went 😉

Save

Save

Send this to a friend