Ruby on Rails

Hire the Top 3% of Freelance Ruby on Rails Developers

Toptal is a marketplace for the best Ruby on Rails developers, engineers, programmers, coders, architects, freelancers, and consultants. Top companies and start-ups choose Toptal Ruby on Rails development services for their mission-critical software projects.

No-Risk Trial, Pay Only If Satisfied.

Clients Rate Toptal Ruby on Rails Developers4.3 / 5.0on average across 785 reviews as of Jun 14, 2023

Hire Freelance Ruby on Rails Developers and Engineers

Dustin Cass

Freelance Ruby on Rails Developer

United StatesToptal Member Since September 26, 2018

Dustin has been a professional front-end engineer for over ten years and has worked at companies and agencies large and small. He's passionate and dedicated to his craft, and he always goes the extra mile for his employers and clients.

Show More

Congwen Ma

Freelance Ruby on Rails Developer

United StatesToptal Member Since March 6, 2018

Congwen is a dedicated web developer specializing in developing full-stack web applications using practical frameworks. He's passionate about solving problems for others. A good solution to Congwen usually requires a dose of creativity that requires more effort to adapt and perfect.

Show More

Trevor Wagner

Freelance Ruby on Rails Developer

United StatesToptal Member Since May 25, 2016

Trevor is a hybrid, a full LAMP stack, and a front-end developer with 10+ years of experience creating custom WordPress themes and plugins and tailoring WordPress admins on a per-client basis. He also specializes in eCommerce on the WooCommerce platform and other large platforms, like SFCC. Trevor is willing to leverage his skillset in new and challenging projects.

Show More

Eqbal Quran

Freelance Ruby on Rails Developer

JordanToptal Member Since June 13, 2014

Eqbal is a senior full-stack developer with more than a decade of experience working in web and mobile development. He is a masterful problem solver and boasts an extensive portfolio of finished professional products.

Show More

Botond Orban

Freelance Ruby on Rails Developer

RomaniaToptal Member Since June 4, 2015

Botond is a highly skilled professional software developer who enjoys writing code that others can understand and follow. His passion for programming began when he was 13, after receiving a ZX Spectrum-compatible Russian PC from his father. He learned programming and became a true lifelong enthusiast.

Show More

Luís Martinho

Freelance Ruby on Rails Developer

PortugalToptal Member Since October 30, 2011

As an entrepreneur, Luís understands the importance of proactivity and results, and has learned the meaning of responsibility and accountability. He is more of a generalist than a specialist, though he loves the detail and deep understanding that comes from intense focus and work on development projects.

Show More

Quang Van

Freelance Ruby on Rails Developer

United StatesToptal Member Since July 18, 2016

Quang enjoys creating beautiful software with equally impressive code. Along with possessing a talent for understanding and refactoring large codebases, he believes in best practices, small functions, and white space. Quang has over 15 years of experience working for marketing, SaaS, healthcare, and crypto companies. He's also founded companies and created social networks, SPAs, membership sites, and marketing tools.

Show More

Sign up now to see more profiles.

Start Hiring
Frequently paired together

Get Additional Expertise

Our clients frequently pair these additional services with our freelance Ruby on Rails Developers.

A Hiring Guide

Guide to Hiring a Great Ruby on Rails Developer

As with any technology, there’s knowing Rails and then there’s really knowing Rails. This guide offers a sampling of questions that are key to evaluating the breadth and depth of a candidate’s mastery of the framework.

Read Hiring Guide

Ruby on Rails Hiring Resources

Trustpilot
Toptal in the press

... allows corporations to quickly assemble teams that have the right skills for specific projects.

Despite accelerating demand for coders, Toptal prides itself on almost Ivy League-level vetting.

Our clients
Building a cross-platform app to be used worldwide
Thierry Jakicevic
Building a cross-platform app to be used worldwide
Testimonials

Tripcents wouldn't exist without Toptal. Toptal Projects enabled us to rapidly develop our foundation with a product manager, lead developer, and senior designer. In just over 60 days we went from concept to Alpha. The speed, knowledge, expertise, and flexibility is second to none. The Toptal team were as part of tripcents as any in-house team member of tripcents. They contributed and took ownership of the development just like everyone else. We will continue to use Toptal. As a start up, they are our secret weapon.

Brantley Pace, CEO & Co-Founder

Tripcents

I am more than pleased with our experience with Toptal. The professional I got to work with was on the phone with me within a couple of hours. I knew after discussing my project with him that he was the candidate I wanted. I hired him immediately and he wasted no time in getting to my project, even going the extra mile by adding some great design elements that enhanced our overall look.

Paul Fenley, Director

K Dunn & Associates

The developers I was paired with were incredible -- smart, driven, and responsive. It used to be hard to find quality engineers and consultants. Now it isn't.

Ryan Rockefeller, CEO

Radeeus

Toptal understood our project needs immediately. We were matched with an exceptional freelancer from Argentina who, from Day 1, immersed himself in our industry, blended seamlessly with our team, understood our vision, and produced top-notch results. Toptal makes connecting with superior developers and programmers very easy.

Jason Kulik, Co-Founder

ProHatch

As a small company with limited resources we can't afford to make expensive mistakes. Toptal provided us with an experienced programmer who was able to hit the ground running and begin contributing immediately. It has been a great experience and one we'd repeat again in a heartbeat.

Stuart Pocknee , Principal

Site Specific Software Solutions

We used Toptal to hire a developer with extensive Amazon Web Services experience. We interviewed four candidates, one of which turned out to be a great fit for our requirements. The process was quick and effective.

Abner Guzmán Rivera, CTO and Chief Scientist

Photo Kharma

Sergio was an awesome developer to work with. Top notch, responsive, and got the work done efficiently.

Dennis Baldwin, Chief Technologist and Co-Founder

PriceBlink

Working with Marcin is a joy. He is competent, professional, flexible, and extremely quick to understand what is required and how to implement it.

André Fischer, CTO

POSTIFY

We needed a expert engineer who could start on our project immediately. Simanas exceeded our expectations with his work. Not having to interview and chase down an expert developer was an excellent time-saver and made everyone feel more comfortable with our choice to switch platforms to utilize a more robust language. Toptal made the process easy and convenient. Toptal is now the first place we look for expert-level help.

Derek Minor, Senior VP of Web Development

Networld Media Group

Toptal's developers and architects have been both very professional and easy to work with. The solution they produced was fairly priced and top quality, reducing our time to launch. Thanks again, Toptal.

Jeremy Wessels, CEO

Kognosi

We had a great experience with Toptal. They paired us with the perfect developer for our application and made the process very easy. It was also easy to extend beyond the initial time frame, and we were able to keep the same contractor throughout our project. We definitely recommend Toptal for finding high quality talent quickly and seamlessly.

Ryan Morrissey, CTO

Applied Business Technologies, LLC

I'm incredibly impressed with Toptal. Our developer communicates with me every day, and is a very powerful coder. He's a true professional and his work is just excellent. 5 stars for Toptal.

Pietro Casoar, CEO

Ronin Play Pty Ltd

Working with Toptal has been a great experience. Prior to using them, I had spent quite some time interviewing other freelancers and wasn't finding what I needed. After engaging with Toptal, they matched me up with the perfect developer in a matter of days. The developer I'm working with not only delivers quality code, but he also makes suggestions on things that I hadn't thought of. It's clear to me that Amaury knows what he is doing. Highly recommended!

George Cheng, CEO

Bulavard, Inc.

As a Toptal qualified front-end developer, I also run my own consulting practice. When clients come to me for help filling key roles on their team, Toptal is the only place I feel comfortable recommending. Toptal's entire candidate pool is the best of the best. Toptal is the best value for money I've found in nearly half a decade of professional online work.

Ethan Brooks, CTO

Langlotz Patent & Trademark Works, Inc.

In Higgle's early days, we needed the best-in-class developers, at affordable rates, in a timely fashion. Toptal delivered!

Lara Aldag, CEO

Higgle

Toptal makes finding a candidate extremely easy and gives you peace-of-mind that they have the skills to deliver. I would definitely recommend their services to anyone looking for highly-skilled developers.

Michael Gluckman, Data Manager

Mxit

Toptal’s ability to rapidly match our project with the best developers was just superb. The developers have become part of our team, and I’m amazed at the level of professional commitment each of them has demonstrated. For those looking to work remotely with the best engineers, look no further than Toptal.

Laurent Alis, Founder

Livepress

Toptal makes finding qualified engineers a breeze. We needed an experienced ASP.NET MVC architect to guide the development of our start-up app, and Toptal had three great candidates for us in less than a week. After making our selection, the engineer was online immediately and hit the ground running. It was so much faster and easier than having to discover and vet candidates ourselves.

Jeff Kelly, Co-Founder

Concerted Solutions

We needed some short-term work in Scala, and Toptal found us a great developer within 24 hours. This simply would not have been possible via any other platform.

Franco Arda, Co-Founder

WhatAdsWork.com

Toptal offers a no-compromise solution to businesses undergoing rapid development and scale. Every engineer we've contracted through Toptal has quickly integrated into our team and held their work to the highest standard of quality while maintaining blazing development speed.

Greg Kimball, Co-Founder

nifti.com

How to Hire Ruby on Rails Developers through Toptal

1

Talk to One of Our Industry Experts

A Toptal director of engineering will work with you to understand your goals, technical needs, and team dynamics.
2

Work With Hand-Selected Talent

Within days, we'll introduce you to the right Ruby on Rails developer for your project. Average time to match is under 24 hours.
3

The Right Fit, Guaranteed

Work with your new Ruby on Rails developer for a trial period (pay only if satisfied), ensuring they're the right fit before starting the engagement.

Find Experts With Related Skills

Access a vast pool of skilled developers in our talent network and hire the top 3% within just 48 hours.

FAQs

  • How are Toptal Ruby on Rails developers different?

    At Toptal, we thoroughly screen our Ruby on Rails developers to ensure we only match you with talent of the highest caliber. Of the more than 200,000 people who apply to join the Toptal network each year, fewer than 3% make the cut. You'll work with engineering experts (never generalized recruiters or HR reps) to understand your goals, technical needs, and team dynamics. The end result: expert vetted talent from our network, custom matched to fit your business needs.

  • Can I hire Ruby on Rails developers in less than 48 hours through Toptal?

    Depending on availability and how fast you can progress, you could start working with a Ruby on Rails developer within 48 hours of signing up.

  • What is the no-risk trial period for Toptal Ruby on Rails developers?

    We make sure that each engagement between you and your Ruby on Rails developer begins with a trial period of up to two weeks. This means that you have time to confirm the engagement will be successful. If you're completely satisfied with the results, we'll bill you for the time and continue the engagement for as long as you'd like. If you're not completely satisfied, you won't be billed. From there, we can either part ways, or we can provide you with another expert who may be a better fit and with whom we will begin a second, no-risk trial.

Share
Ruby on Rails

How to Hire a Great Ruby on Rails Developer

The Technology

Just as France’s Train à Grande Vitesse (TGV) (traveling at speeds of up to 320 km/h) dramatically reduces travel time for modern day rail passengers, Ruby on Rails (a.k.a. “Rails”) substantially reduces the time and effort required to build powerful web applications. Tim O’Reilly (founder of O’Reilly Media) refers to Rails as breakthrough technology and Gartner Research noted in a recent study that many high-profile companies are using Rails to build agile, scalable web applications.

The rate at which Rails has gained popularity is noteworthy, with estimates of over 200,000 web sites currently built with the technology. Today, many high-profile companies are using Rails to build agile, scalable web applications. Examples include Twitter, GitHub, Yammer, Scribd, Groupon, Shopify, and Basecamp, to name but a few.

Rails is a framework for web application development, written in Ruby, that also features its own routing system independent of the web server. The goal of Rails is to significantly simplify the development of web applications, requiring less code and time than would otherwise be required to accomplish the same tasks.

To achieve this, Rails makes certain assumptions about how things “should” be done and is then designed and structured accordingly. While imbibing this “Rails view of the world” can sometimes be a bit of a culture shock for developers strongly grounded in other languages and frameworks, over time most come to greatly appreciate the Rails approach and the productivity that it engenders.

The Challenge

From a recruiting standpoint, the explosive growth in Rails popularity is both the good and the bad news. While on the one hand it makes Rails developers easier to locate, it also makes finding the top-notch jewels among them that much more elusive.

Finding true high-quality Rails experts for full-time or part-time work requires a highly-effective recruiting process, as described in our post In Search of the Elite Few – Finding and Hiring the Best Developers in the Industry. Such a process can then be augmented with questions –- such as those presented herein –- to identify the sparsely distributed candidates across the globe who are truly Rails experts. The manifold benefits of finding them will likely be realized in the productivity and results that they will be able to achieve.

Yeah, I know Rails…

The extent to which Rails streamlines and simplifies the development of web applications can mislead neophyte developers into underestimating its capabilities and oversimplifying its conceptual underpinnings. While Rails is relatively easy to use, it is anything but simplistic.

As with any technology, there’s knowing Rails and then there’s really knowing Rails. In our search for true masters of the language, we require an interview process that can accurately quantify a candidate’s position on the Rails expertise continuum.

Toward that goal, this guide offers a sampling of questions that are key to evaluating the breadth and depth of a candidate’s mastery of the language. It is important to bear in mind, though, that these sample questions are intended merely as a guide. Not every “A” candidate worth hiring will be able to properly answer them all, nor does answering them all guarantee an “A” candidate. At the end of the day, hiring remains as much of an art as it does a science.

Frequent Rail Traveler?

It is not uncommon to encounter RoR developers whose grasp of the fundamentals and key paradigms of Rails are either weak or somewhat confused.

Questions that can help assess a developer’s grasp of the Rails foundation, including some of its more subtle nuances, are therefore an important component of the interview process.

Here are some examples:

Q: Explain the processing flow of a Rails request.

At the highest level, Rails requests are served through an application server, which is responsible for directing an incoming request into a Ruby process. Popular application servers that use the Rack web request interface include Phusion Passenger, Mongrel, Thin, and Unicorn.

Rack parses all request parameters (as well as posted data, CGI parameters, and other potentially useful bits of information) and transforms them into a big Hash (Ruby’s record / dictionary type). This is sometimes called the env hash, as it contains data about the environment of the web request.

In addition to this request parsing, Rack is configurable, allowing for certain requests to be directed to specific Rack apps. If you want, for example, to redirect requests for anything in your admin section to another Rails app, you can do so at the Rack level. You can also declare middleware here, in addition to being able to declare it in Rails.

Those requests that are not directed elsewhere (by you in Rack) are directed to your Rails app where it begins interacting with the Rails ActionDispatcher, which examines the route. Rails apps can be spit into separate Rails Engines, and the router sends the request off to the right engine. (You can also redirect requests to other Rack compatible web frameworks here.)

Once in your app, Rails middleware – or your custom middleware – is executed. The router determines what Rails controller / action method should be called to process the request, instantiates the proper controller object, executes all the filters involved, and finally calls the appropriate the action method.

Further detail is available in the Rails documentation.

Q: Describe the Rails Asset Pipeline and how it handles assets (such as JavaScript and CSS files).

Rails 3.1 introduced the Asset Pipeline, a way to organize and process front-end assets. It provides an import/require mechanism (to load dependent files) that provides many features. While the Asset Pipeline does have its rough edges, it does solve and provide many of the modern best practices in serving these files under HTTP 1.1. Most significantly, the Asset Pipeline will:

  • Collect, concatenate, and minify all assets of each type into one big file
  • Version files using fingerprinting to bust old versions of the file in browser caches

The Asset Pipeline automatically brings with it Rails’ selection of Coffeescript as its JavaScript pre-processed / transpiled language of choice and SASS as its CSS transpiled language. However, being an extensible framework, it does allow for additional transpiled languages or additional file sources. For example, Rails Assets brings the power of Bower to your Rails apps, allowing you to manage third-party JavaScript and CSS assets very easily.

Q: What is Active Record and what is Arel? Describe the capabilities of each.

Active Record was described by Martin Fowler in his book Patterns of Enterprise Application Architecture as “an object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data”.

ActiveRecord is both an Object Relational Mapping (ORM) design pattern, and Rails’ implementation of that design pattern. This means that fetching, querying, and storing your objects in the database is as much a part of the API of your objects as your custom business logic. A developer may see this as an undesired side effect, or as a welcome convention, depending on their preference and level of experience.

Arel provides a query API for ActiveRecord, allowing Ruby on Rails development experts to perform database queries without having to hand-write SQL. Arel creates lazily-executed SQL whereby Rails waits until the last possible second to send the SQL to the server for execution. This allows you to take an Arel query and add another SQL condition or sort to the query, right up to the point where Rails actually executes the query. Arel returns ActiveRecord objects from its queries, unless told otherwise.

Q: What is the Convention over Configuration pattern? Provide examples of how it is applied in Rails.

Convention over Configuration (CoC) is a software design pattern by which only the unconventional aspects of an application need to be specified by a developer. When the default convention matches the desired behavior, the default behavior is followed without any configuration being required. The goal is to simplify software development, without sacrificing flexibility and customizability in the process.

Here are some examples of how CoC principles are applied in Rails:

  • Model and database table naming. Rails automatically pluralizes class names to find the respective database tables. For a class Book, for example, it will expect a database table named books. For class names composed of multiple words, the model class name should employ CamelCase (e.g., BookClub and book_clubs).
  • Primary and foreign keys. By default, Rails uses an integer column named id as the table’s primary key. Foreign key names by default follow the pattern of appending _id to the singularized tablename (e.g., item_id for a foreign key into the items table).
  • Reserved words for automatic functionality. There are also some optional column names which, if used, automatically add features and functionality to Rails database tables. created_at, for example, will automatically be set to the date and time when the record was created. Similarly, updated_at will automatically be set to the date and time whenever the record was last updated.
  • Auto-loading of class definitions. Auto-loading is the “magic” by which classes appear to be accessible from anywhere, without the need to explicitly require them. Here’s how it works: When you reference a class in your code, Rails takes the class name (with namespace) as a string, calls underscore on it, and looks for a file with that name (in all directories specified in your config.autoload_paths). For example, if you reference a class named FileHandling::ZipHandler, Rails will automatically search for file_handling/zip_handler.rb in your config.autoload_paths. This feature often results in novice Rails programmers thinking that they don’t need to explicitly require referenced classes and that Rails will just auto-magically find them anyway. They then become baffled when they don’t follow this convention and are suddenly being told by Rails that their classes can’t be found.

It is important to note that CoC specifies a default –- but not immutable –- convention. Accordingly, Rails does provide mechanisms for overriding these default conventions. As an example, the default database table naming scheme mentioned above can be overridden by specifying the ActiveRecord::Base.table_name as shown here:

class Product < ActiveRecord::Base
  self.table_name = "LEGACY_PRODUCT_TABLE"
end

Q: What is the “fat model, skinny controller” approach? Discuss some of its advantages and pitfalls, as well as some alternatives.

“Fat model skinny controller” is an MVC-based Rails design pattern.

MVC is itself a software design pattern that separates a system into three separate and distinct layers; namely, Model, View, and Controller. MVC strives to ensure a clean separation between each of its layers through clearly defined APIs. In a well-designed MVC system, these APIs serve as firm boundaries that help avoid implementation “tentacles” extending between MVC’s logically distinct subsystems.

The “Fat model skinny controller” design pattern advocates placing as much logic as possible in the Model for (a) maximum reuse and (b) code that is easier to test.

That said, a common pitfall for Rails developers is to end up with “overly bloated” models by adhering too blindly to the “fat model, skinny controller” paradigm. The infamous User model is a prime example of this. Since many Rails apps are about the user entering data into the system, or sharing information with their friends socially, the user model will often gain more and more methods, eventually reaching the point where the user.rb model becomes bulky and unmanageable in size.

A few key alternatives worth considering include:

  • Use of other objects: Extract functionality out of models into other objects (such as Decorators or Service objects)
  • Hexagonal architecture for Rails: Employ a hexagonal architecture that views the application as a hexagon, each side of which represents some sort of external interaction the application needs to have.
  • DCI (Data Context Interaction): Instead of focusing on individual objects, focus on the communication and interactions between data and its context.

Q: Describe the Rails testing philosophy.

Rails built testing support in from the beginning of the framework, and it became a part of the culture. As a result, there are a plethora of tools available for testing in the Rails environment.

By default, Rails 4.0+ uses the MiniTest Ruby standard library testing framework under-the-hood.

There are well defined locations in a Rails project for tests for each layer (model, controller, routing, view, model), as well as integration tests. Because of the MVC foundation of Rails, often these layers (with the exception of integration tests) can be tested without reliance on the other layers.

For example, we can create a database record, before the test runs, that contains the attributes we expect the test to return. Our test can focus on making sure our show post controller action retrieves the post we want it to by checking to see if it returns the object we created above as expected. If not, something went wrong or our code must have a bug. Here’s an example of such a test:

class PostsControllerTest < ActionController::TestCase
  setup do
    @post = posts(:one)
  end

  test "should show post" do
    get :show, id: @post
    assert_response :success
  end
end

Integration tests (often called Feature tests) will usually drive the application as if a user is clicking buttons, using testing tools like Capybara (which can simulate user actions in a variety of manners, including driving embedded WebKit, or using Selenium).

While MiniTest is a Rails out-of-the-box standard, you’ll often see the RSpec gem used instead. This provides a Domain Specific Language for testing that may make it more natural to read than MiniTest.

Some Rails projects use the Cucumber testing framework to describe software behavior in plain English sentences. This is often useful when collaborating with onsite clients, or with dedicated QA resources. In the ideal world, these non-developers can write automated integration tests without having to see a line of Ruby code.

Down on the tracks

Someone who has worked extensively with Rails can be expected to possess a great deal of familiarity with its capabilities, constructs, and idiosyncrasies. These questions demonstrate ways of gauging the extent and depth of this expertise.

Q: Explain the use of yield and content_for in layouts. Provide examples.

yield identifies where content from the view should be inserted. The simplest approach is to have a single yield, into which the entire contents of the view currently being rendered is inserted, as follows:

<html>
  <head>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

You can also create a layout with multiple yielding regions:

<html>
  <head>
        <%= yield :head %>
  </head>
  <body>
        <%= yield %>
  </body>
</html>

The main body of the view will always render into the unnamed yield. To render content into a named yield, use the content_for method. content_for allows for insertion of content into a named yield block in a layout. This can be helpful with layouts that contain distinct regions, such as sidebars and footers, into which distinct blocks of content are to be inserted. It can also be useful for inserting tags that load page-specific JavaScript or CSS files into the header of an otherwise generic layout.

Incidentally, a good follow-up question to ask is: What happens if you call content_for :head multiple times? The answer is that all of the values get concatenated.

Q: What are N+1 queries, and how can you avoid them?

Consider the following code, which finds 10 clients and prints their postal codes:

clients = Client.limit(10)
clients.each do |client|
  puts client.address.postcode
end

This code actually executes 11 queries; 1 (to find 10 clients) and then 10 more (one per each client to load its address). This is referred to as an “N+1 query” (where in the case of this example, N is 10).

Eager loading is the mechanism for loading the associated records of the objects returned by Model.find using as few queries as possible.

Active Record’s eager loading capability makes it possible to significantly reduce the number of queries by letting you specify in advance all the associations that are going to be loaded. This is done by calling the includes (or preload) method on the Arel (ActiveRecord::Relation) object being built. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.

We could therefore rewrite the above code to use the includes method as follows:

clients = Client.includes(:address).limit(10)
clients.each do |client|
  puts client.address.postcode
end

This revised version of this code will execute just 2 queries, thanks to eager loading, as opposed to 11 queries in the original version.

Q: What are “filters” in Rails? Describe the three types of filters, including how and why each might be used, and the order in which they are executed. Provide examples.

Filters are essentially callback methods that are run before, after, or “around” a controller action:

  • Before filter methods are run before a controller action and therefore may halt the request cycle. A common before filter is one which requires a user to be logged in for an action to be performed.
  • After filter methods are run after a controller action and therefore cannot stop the action from being performed but do have access to the response data that is about to be sent to the client.
  • Around filter methods are “wrapped around” a controller action. They can therefore control the execution of an action as well as execute code before and/or after the action is performed.

For example, in a website where changes have an approval workflow, an administrator could be able to preview them easily with an around filter as follows:

class ChangesController < ApplicationController
  around_action :wrap_in_transaction, only: :show

  private

  def wrap_in_transaction
        ActiveRecord::Base.transaction do
          begin
            yield
          ensure
            raise ActiveRecord::Rollback
          end
        end
  end
end

Note that an around filter also wraps rendering. In particular, in the example above, if the view reads from the database (e.g., via a scope), it will do so within the transaction and thus present the data to preview. You can also choose not to yield and build the response yourself, in which case the action will not be run.

The order of execution is a bit tricky and is important to understand clearly. Filter methods execute in the following order:

  1. Before filter methods, in order of definition.
  2. Around filter methods, in order of definition.
  3. After filter methods, in reverse order.

Also, because of the way Ruby instantiates classes, the filter methods of a parent class’ before will be run before those of its child classes.

Q: What is Rack middleware? How does it compare to controller filters/actions?

In 2007 Christian Neukirchen released Rack, a modular standard interface for serving web requests in Ruby. Rack is similar to other similar mechanisms in other languages, such as WSGI on the Python side, or Java Servlets, or Microsoft’s Internet Server Application Programming Interface (ISAPI).

Before requests are processed by your Rails action method, they go through various Rack middleware functions declared by Rails or by the developer. Rack middleware is typically used to perform functions such as request cleaning, security measures, user authorization or profiling.

You can see a list of available middleware components (both developer defined and those defined by Rails) by running rake middleware on the command line.

A key distinction between Rack middleware and filters is that Rack middleware is called before Rails does its routing and dispatching, whereas filters are invoked after this routing has occurred (i.e., when Rails is about to call your controller action method). As such, its is advantageous to filter out requests to be ignored in middleware whenever possible, such as requests from common attack URLs (phpadmin.php requests, for example, can be discarded in middleware, as they will never resolve in a Rails app and is probably just some attempt to hack the site.)

Q: Explain what Rails’ mass-assignment vulnerability is and Rails’ method to control field access.

When the user performs a post (such as, for example, creating a new User) Rails needs to save all that new data into the database. This data is accessible from your Rails action via the params Hash.

Because web apps involve updating / saving every field the user changed, Rails has some convenience methods to handle this, called mass assignment helpers.

For example, prior to Rails 4, creating a new User object with parameters from a submitted form looked like:

User.create(params[:user])

params[:user] will contain keys for the elements the user entered on the form. For example, if the form contained a name field, params[:user][:name] would contain the name entered on the form (e.g., “Jeff Smith”).

Convention vs. configuration strikes again here: name is the name of both the input element in the form and the name of the column in the database.

In addition to the create method, you can update a record the same way:

@user = User.find(params[:id])
@user.update_attributes(params[:user])

But what happens when a hacker goes in and edits your HTML form to add new fields? They may, for example, guess that you have an is_admin field, and add it to the HTML form field themselves. Which now means that – even though you didn’t include it on the form that’s served to users – your hacker has gone in and made themselves an admin on your site!

This is referred to as mass assignment vulnerability; i.e., assigning all these fields with no filtering en masse, just trusting that the only field names and values will be those that were legitimately on the HTML form.

Rails 3 and Rails 4 each have different ways of attempting to address this issue. Rails 3 attempted to address it via attr_protected / attr_accessible controls at the model level, while Rails 4 addresses it via strong parameters and a filtering mechanism at the controller level. Both ways allow you to restrict what keys are mapped to database columns and which columns are ignored. Using these mechanisms, in the prior is_admin example, you can set the is_admin field to only change when code explicitly modifies the field value, or only allow it to be changed in certain situations.

The Big Picture

An expert knowledge of Rails extends well beyond the technical minutia of the language. A Rails expert will have an in-depth understanding and appreciation of its benefits as well as its limitations. Accordingly, here are some sample questions that can help assess this dimension of a candidate’s expertise.

Q: Why do some people say “Rails can’t scale”?

Twitter was one of the first extremely high profile sites to use Rails. In roughly the 2006-2008 timeframe, the growth rate of Twitter made server errors (“fail whale”) appearances a very common occurrence for users, prompting users and tech pundits to lay blame at Rails’ feet. As is true with any software, the causes of scalability issues can be complex and multi-faceted. Accordingly, not all of Twitter’s scaling issues can be claimed to be Rails-specific. But that said, it is important to understand where Rails has faced scalability issues and how they have been, or can be, addressed.

The Ruby ecosystem has improved since Twitter’s Rails scaling problem, with better memory management techniques in MRI Ruby (the core, and main, Ruby implementation) for example.

Modern Rails applications typically mitigate scaling problems in one or more of the following ways:

  • Implementing caching solutions (Rails 4 introduces good advances here)
  • Leveraging (or implementing) server or platform solutions with automatic scaling built in
  • Profiling costly operations and moving them out of Ruby or out of one monolithic Rails app
  • Placing some operations in a background / worker queue to be completed at a later time (e.g., perform an export operation asynchronously, notifying the user by email with a download link when the export is completed)

While there has traditionally been a one-to-one mapping between websites and RoR applications (i.e., one website = one Rails app), there’s been an increasing movement towards more of a Service Oriented Architecture (SOA) approach whereby performance critical parts of the app are split off into new/separate apps which the main app usually talks to via web service calls. There are numerous advantages to this approach. Perhaps most noteworthy is the fact that these independent services can employ alternate technologies as appropriate; this might be a lightweight / more responsive solution in Ruby, or services written in Scala (as in Twitter’s case), or Node.js, Clojure, or Go.

But writing separate services isn’t the only way to speed up a Rails app. For example, Github has an interesting article on how it profiled Rails and ended up implementing a set of C apis for performing text escaping on the web.

Q: When is Rails a good choice for a project?

Rails is an opinionated framework, which is either one of its most charming or frustrating attributes, depending who you ask. Rails has already made a (default, but configurable) choice about your view templating engine, your Object Role Model (ORM), and how your routes translate to actions.

As a result of these choices, Rails is a great choice for a project where your application has total control over its own database, mostly returns HTML (or at least doesn’t solely return JSON), and for the most part displays data back to the users consistently with the way it is stored.

Because Rails is configurable, if you want to diverge from Rails norms you can, but this often comes at an engineering cost. Want to hook into an existing MS SQL database? You can do that, but you’ll hit some bumps along the way. Want to build a single page app with Rails, returning mostly JSON object? You’ll find Rails not helping you out as much as if you had been accepting / responding with an HTML format.

Q: What are some of the drawbacks of Rails?

Rails is generally meant for codebases of greater than a few hundred lines of code, and that primarily work with its own database objects. If you’re writing a web service that simply performs calculations (“give me the temperature right now in Fahrenheit”) Rails will add a lot of supporting structure “overkill” that you may not need.

Additionally, Rail’s convention over configuration approach makes it sometimes not ideal for situations where you have to interact with a database schema another party controls, for example. Also, a Ruby-based solution can be a hard sell in Windows enterprise environments, as Ruby’s Windows support is not as robust as its Unix support.

Like Python, the concurrency story in the default Ruby implementation (MRI; a.k.a. CRuby) is somewhat hobbled by a Global Interpreter Lock (GIL), which in broad strokes means only one thread can execute Ruby code at a time. (JRuby and Rubinius, other implementations of Ruby, have no GIL.

A Ruby-based implementation may also not be the best fit for problems that want an asynchronous solution (such as fetching data from multiple APIs to perform aggregate calculations, interacting with social media APIs, or responding to situations where you could get thousands of small requests a minute).

Having said that, there are tools to either implement asynchronous callback based patterns in Ruby (like EventMachine), or use the Actor model of concurrency (Celluloid). And of course there are a number of background worker mechanisms if your problem fits in that space.

And finally… Ruby Rookie or Gemologist?

Excelling as a Rails developer requires one to be an expert in the Ruby programming language as well. Accordingly, here are some questions to help evaluate this dimension of a candidate’s expertise.

Q: What are Ruby mixins, how do they work, and how would you use them? What are some advantages of using them and what are some potential problems? Give examples to support your answers.

A “mixin” is the term used in Ruby for a module included in another class. When a class includes a module, it thereby “mixes in” (i.e., incorporates) all of its methods and constants. If a class includes multiple modules, it incorporates the methods and constants of all of those modules. Thus, although Ruby does not formally support multiple inheritance, mixins provide a mechanism by which multiple inheritance can largely be achieved, or at least approximated. (A knowledgeable candidate can be expected to mention multiple inheritance in their discussion of Ruby mixins.)

Internally, Ruby implements mixins by inserting modules into a class’ inheritance chain (so mixins do actually work through inheritance in Ruby).

Consider this simple example:

module Student
  def gpa
    # ...
  end
end

class DoctoralStudent
  include Student
  def thesis
    # ...
  end
end

phd = DoctoralStudent.new

In this example, the methods of the Student class are incorporated into DoctoralStudent class, so the phd object supports the gpa method.

It is important to note that, in Ruby, the require statement is the logical equivalent of the include statement in other languages. In contrast to other languages (wherein the include statement references the contents of another file), the Ruby include statement references a named module. Therefore:

  • The module referenced by an include statement may either be in the same file (as the class that is including it) or in a different file. If in a different file, a require statement must also be used to properly incorporate the contents of that file.
  • A Ruby include makes a reference from the class to the included module. As a result, if the definition of a method in the included module is modified, even at runtime, all classes that include that module will exhibit the new behavior when that method is invoked.

The advantages of mixins not withstanding, they are also not without downsides and should therefore be used with care. Some potential pitfalls include:

  • Instance variable name collisions. Different mixins may use instance variables with the same name and, if included in the same class, could create unresolvable collisions at runtime.
  • Silent overriding of methods. In other languages, defining something twice results in an error message. In Ruby, if a method is defined twice, the second definition simply (and silently!) overwrites the first definition. Method name clashes across multiple mixins in Ruby are therefore not simple errors, but instead can introduce elusive and gnarly bugs.
  • Class bloat. The ease-of-use of mixins can also lead to their “abuse”. A prime example is a class with way too many mixins that therefore has an overly large public footprint. The rules of coupling and cohesion start to come into play, and you can end up with a system where changes to a module that’s frequently included can have disastrous effects. Traditional inheritance or composition is much less prone to this type of bloat. Quite often extracting parts of a class into modules that are mixed in is akin to cleaning your room by putting the mess into large bins. It looks clean until you start opening the bins.

Q: Compare and contrast Symbols and Strings in Ruby? Why use one vs. the other?

Symbols are singleton based on value, and immutable objects. Unlike strings, not all symbols may be garbage collected.

Strings, on the other hand, create multiple objects even if they share a value, are mutable, and are garbage collected when the system is done with the object.

Since symbols are singleton based on value (there is only one symbol object for a value, even if it appears multiple times in a program), this makes it trivial to compare whether two symbols are the same (Ruby basically just needs to compare their object_id values). Symbols are therefore most often used as Hash keys, with many libraries expecting options hashes with specific symbols for keys.

Strings can be made immutable (“frozen”) via the freeze method. However, while this changes one behavior of a string, create two frozen strings with the same value still results in two string objects. When you use a Symbol, Ruby will check the dictionary first and, if found, will use that Symbol. If the Symbol is not found in the dictionary, only then will the interpreter instantiate a new Symbol and put it in the heap.

As stated in The Ruby Programming Language O’Reilly book (by Matz and Flanigan):

A typical implementation of a Ruby interpreter maintains a symbol table in which it stores the names of all the classes, methods, and variables it knows about. This allows such an interpreter to avoid most string comparisons: it refers to method names (for example) by their position in this symbol table. This turns a relatively expensive string operation into a relatively cheap integer operation.

Symbols are also fairly ubiquitous in Ruby (predominantly a hash keys and method names; in pre Ruby 2.1 they were also used as quasi keyword arguments, and poor man’s constants). Because of their performance, memory and usage considerations, Symbols are most often used as Hash keys, with many libraries expecting option hashes with specific symbols for keys.

Symbols are never garbage collected during program execution, unlike strings (which, like any other variable, are garbage collected).

Because strings and symbols are different objects, here’s an example of something that often catches less experienced Ruby programmers unaware.

Consider the following hash, for example:

irb(main):001:0> a = {:key => 1}
irb(main):002:0> puts a['key']
=> nil.

You may be expecting to see 1 printed here, especially if a was defined elsewhere in your program. But, as strings and symbols are different; i.e., key (the symbol) and 'key' (the string) are not equivalent. Accordingly, Ruby correctly returns nil for a['key'] (even though this is annoying for the unsuspecting programmer wondering where her value is!)

Rails has a class, HashWithIndifferentAccess, which acts like a Hash object, except it treats strings and symbols with the same values as equivalent when used as key names, thereby avoiding the above issue:

irb(main):001:0> a = HashWithIndifferentAccess.new({:key => 1})
irb(main):002:0> puts a['key']
=> 1

There is one important caveat. Consider this controller action:

def check_value
  valid_values = [:bad, :ok, :excellent]
  render json: valid_values.include?(params[:value].to_sym)
end

This innocent looking code is actually a denial-of-service (DOS) attack vulnerability. Since symbols can never be garbage collected (and since here we cast user input into a symbol), a user can keep feeding this endpoint with unique values and it will eventually eat up enough memory to crash the server, or at least bring it to a grinding halt.

Q: Describe multiple ways to define an instance method in Ruby.

Instance methods can of course be defined as part of a class definition. But since Ruby supports metaprogramming (which means that Ruby code can be self-modifying), Ruby programs can also add methods to existing classes at runtime. Accordingly, there are multiple techniques for defining methods in Ruby, as follows:

(1) Within a class definition, using def (The simplest answer)

class MyObject

  def my_method
    puts "hi"
  end
end

This is the standard way to define instance methods of a class.

(2) Within a class definition, without using def

class MyObject
  define_method :my_method do
    puts "hi"
  end
end

Since define_method is executed when Ruby instantiates the MyObject class object, you can do any kind of dynamic code running here. For example, here’s some code that only creates our method if it’s being run on a Monday:

require 'date'

class MyObject
  if Date.today.monday?
    define_method :my_method do
      puts "Someone has a case of the Mondays"
    end
  end
end

Starting the application on any other day of the week will make executing MyObject.new.my_method raise an exception about no such method existing (even if it is executed on Monday). Which is true: It’ll only exist if the class body was evaluated on a Monday!

(It’s important to note that classes are objects too in Ruby, so our MyObject class is an instantiation of a Class object, just like in a = MyObject.new, a is an instance of MyObject.)

(3) Extending an existing class definition

Ruby also allows class definitions to be extended. For example:

class MyObject
  def say_hello
    puts "hey there!"
  end
end

class MyObject
  def say_goodbye
    puts "buh-bye"
  end
end

The above code will result in the MyObject class having both the say_hello and the say_goodbye methods defined.

Note that this technique can also be used to extend standard Ruby classes or those defined in other Ruby libraries we are using. For example, here we add a squawk method to the standard Ruby string class:

class String

  def squawk
    puts "SQUAWK!!!"
  end
end

"hello".squawk

(4) Using class_eval

class_eval dynamically evaluates the specified string or block of code and can therefore be used to add methods to a class.

For example, we can define the class MyObject:

class MyObject
  ...
end

… and then come back at a later time and run some code to dynamically add my_method to the MyObject class:

MyObject.class_eval do
  def my_method
    puts "hi"
  end
end

(5) Using method missing

Ruby also provides a hook to check for undefined methods. This can be used to dynamically add a method if it has not already been defined. For example:

class MyObect
  def method_missing(method_name_as_symbol, *params)
    if method_name_as_symbol == :my_method
      puts "hi"
    end
  end
end

Wrap Up

Ruby on Rails is a powerful framework for rapid web development. While all developers can benefit from its ease-of-use and flexibility, as with any technology, those who have truly mastered it and the development process will realize the greatest potential and productivity in its use.

While no brief guide such as this can entirely cover the breadth and depth of technical topics to cover in an interview to hire RoR developers, the questions provided herein offer an effective basis for identifying those who possess a sound and principled foundation in the Rails framework and its paradigms.

Top Ruby on Rails Developers are in High Demand.

Start Hiring