Rails now provides pattern matching support for ActiveModel

The most important feature that was released in Ruby 2.7 was Pattern Matching. This feature is common in most functional programming languages such as Scala, Elixir, etc.

In Ruby, Pattern matching is the way to recognize a pattern of data and execute some actions if the data matches the pattern. Pattern matching in Ruby is performed using the case statement wherein the keyword in is used instead of when to match patterns.

An example of pattern matching in Ruby,

case ['apple', 'mango', 'orange', 'guava']
in ['mango', 'apple', 'orange', 'guava']
  puts "Fruits in incorrect order"
in ['apple', 'mango', 'orange', 'guava']
  puts "Fruits in correct order"

#=> "Fruits in the correct order"

case [1, 2, 3, 4]
in [1, 3, *other_numbers]
  puts "Incorrect match"
in [1, *other_numbers]
  puts "Correct match"
  puts other_numbers
#=> "Correct match"
#=> 2
#=> 3
#=> 4

point = { x: 1, y: 2, z: 3 }
case point
in { x:, y:, z: }
  puts "The points are #{x}, #{y}, #{z}"
  puts "The pattern are not matched correctly"

#=> "The points are 1, 2, 3"

This feature was introduced in 2.7 and the Ruby community loves this feature as it makes the code more readable. Rails will now allow the same pattern matching feature against ActiveModel (also ActiveRecord) objects.

To understand how this could help the Rails codebase, let’s take an example of a User model with the following attributes-

  1. type
  2. preferred_full_name
  3. first_name
  4. last_name
class User
  include ActiveModel::AttributeMethods

  attr_accessor :type, :preferred_full_name, :first_name, :last_name

We need to define a method to get a User’s full name but with the following conditions

  1. If type is “Employer”, then return “Name not required”
  2. If type is “Employee” and preferred_full_name is given then return the preferred_full_name
  3. If type is “Employee” and first_name and last_name is given, then return the full name with first_name and the last_name
  4. If none of these scenarios are matched, return “Name not found”


Before it’s latest version, the following code was used to create this method-

def get_employee_name(user)
  if user[:type] == "Employer"
    return "Name not required"
  elsif user[:type] == "Employee"
    if user[:preferred_full_name]
      return user[:preferred_full_name]
    elsif user[:first_name] && user[:last_name]
      return "#{user[:first_name]} #{user[:last_name]}"
  return "Name not found"


After the latest Rails version is released, the above method can become more readable using Pattern Matching.

def get_employee_name(user)
  case user
  in { type: "Employer" }
    return "Name not required"
  in { type: "Employee", preferred_full_name: }
    return preferred_full_name
  in { first_name:, last_name: }
    return "#{first_name} #{last_name}"
    return "Name not found"

user = User.new(type: "Employer", preferred_full_name: "Smith John", first_name: "John", last_name: "Smith")
get_employee(user) #=> "Name not required"

user = User.new(type: "Employee", preferred_full_name: "Smith John", first_name: "John", last_name: "Smith")
get_employee(user) #=> "Smith John"

user = User.new(type: "Employee", first_name: "John", last_name: "Smith")
get_employee(user) #=> "John Smith"

user = User.new(type: "Employee")
get_employee(user) #=> "Name not found"

The above method makes the code more readable and easy to understand. This enhancement helps a lot in writing methods with complex logic much easier.

Note: The enhancement is yet to be released in the official Rails version

Check out the PR for more details.

Join Our Newsletter