---
title: "Rails 6.1 adds delegated_type to ActiveRecord"
description: "Rails 6.1 adds delegated_type to ActiveRecord"
canonical_url: "https://www.bigbinary.com/blog/rails-6-1-adds-delegated-type-to-active-record"
markdown_url: "https://www.bigbinary.com/blog/rails-6-1-adds-delegated-type-to-active-record.md"
---

# Rails 6.1 adds delegated_type to ActiveRecord

Rails 6.1 adds delegated_type to ActiveRecord

- Author: Akhil Gautam
- Published: April 6, 2021
- Categories: Rails, Rails 6.1

Rails 6.1 adds `delegated_type` to ActiveRecord which makes it easier for models
to share responsibilities.

## Before Rails 6.1

Let's say we are building software to manage the inventory of an automobile
company. It produces 2 types of vehicles, `Car` and `Motorcycle`. Both have
`name` and `mileage` attributes.

Let's look into at least 2 different solutions to design this system.

<br />

### Single Table Inheritance

In this approach, we combine all the attributes of various models and store them
in a single table. Let's create a `Vehicle` model and its corresponding table to
store the data of both `Car` and `Motorcycle`.

```ruby
# schema of Vehicle {id: Integer, type: String[car or motorcycle], name: String, mileage: Integer}
class Vehicle < ApplicationRecord
  # put common logic here
end

class Car < Vehicle
  # put car specific code & validation
end

class Motorcycle < Vehicle
  # put motorcycle-specific code & validation
end
```

This approach fits precisely for this scenario but when the attributes of the
various models differ, it becomes a pain point. Let's say at some point in time
we add a `bs4_engine` boolean column to track whether a `Motorcyle` has a
`bs4_engine` or not. In the case of `Car`, `bs4_engine` will contain `nil`. As
time passes, a lot of vehicle-specific attributes get added and the database
will be sparsely filled with a lot of `nil`.

### Polymorphic Relations

With polymorphic associations, a model can belong to more than one other model,
on a single association.

```ruby
# schema {name: String, mileage: Integer}
class Vehicle < ApplicationRecord
  belongs_to :vehicleable, polymorphic: true
end

# schema {interior_color: String, adjustable_roof: Boolean}
class Car < ApplicationRecord
  has_one :vehicle, as: :vehicleable
end

# schema {bs4_engine: Boolean, tank_color: String}
class Motorcycle < ApplicationRecord
  has_one :vehicle, as: :vehicleable
end
```

Here, `Vehicle` is a class that contains common attributes, while `Motorcycle`
and `Car` store any diverging attributes. This approach fixes the `nil` values,
but to create a `Vehicle` record we now have to create a `Car` or `Motorcycle`
first separately.

```ruby
# creating new records
>> bike = Motorcycle.create!( bs4_engine: false, tank_color: '#f2f2f2')
#<Motorcycle id: 1, bs4_engine: true, tank_color: '#f2f2f2', created_at: "2021-01-17 ...">

>> vehicle = Vehicle.create!(vehicleable: bike, name: 'TS-1987', mileage: 45)
#<Vehicle id: 1, vehicleable_type: "Motorcycle", vehicleable_id: 1, name: "TS-1987", mileage: 45, created_at: ...">

# query
>> b1 = Motorcycle.find(1) #=> <Motorcycle id: 1, bs4_engine: true, tank_color: '#f2f2f2', created_at: "2021-01-17 ...">
>> b1.vehicle.name  #=> TS-1987
>> b1.vehicle.mileage  #=> 45
```

Now, let's say, we need to query Vehicles that are Motorcycles, or let's say we
want to check whether a Vehicle is a Car or not. For all of these, we will have
to write cumbersome logic and queries.

## Rails 6.1 `delegated_type`

Rails 6.1 brings `delegated_type` which fixes the problem discussed above and
adds a lot of helper methods. To use it, we just need to replace polymorphic
relation with `delegated_types`.

```ruby
class Vehicle < ApplicationRecord
  delegated_type :vehicleable, types: %w[ Motorcycle Car ]
end
```

That is the only change we need to make to leverage the `delegated_type`. With
this change, we can create both the delegator and delegatee at the same time.

```ruby
# creating new records
>> vehicle1 = Vehicle.create!(vehicleable: Car.new(interior_color: '#fff', adjustable_roof: true), name: 'TS78Z', mileage: 89)
#<Vehicle id: 3, vehicleable_type: "Car", vehicleable_id: 2, name: "TS78Z", mileage: 89, created_at: ...">

>> vehicle2= Vehicle.create!(vehicleable: Motorcycle.new(bs4_engine: false, tank_color: '#ff00bb'), name: 'BL96', mileage: 45)
#<Vehicle id: 4, vehicleable_type: "Motorcycle", vehicleable_id: 5, name: "BL96", mileage: 45, created_at: ...">

# Note: Just initializing the delegatee(Car.new/Motorcycle.new) is sufficient.
```

When it comes to query capabilities, it adds a lot of delegated type convenience
methods.

```ruby
# Get all Vehicles that are Cars
>> Vehicle.cars
#<ActiveRecord::Relation [#<Vehicle id: 5, vehicleable_type: "Car", vehicleable_id: 1, name: "TS78Z", ...">]>

# Get all Vehicles that are Motorcycles
>> Vehicle.motorcycles
#<ActiveRecord::Relation [#<Vehicle id: 1, vehicleable_type: "Motorcycle", vehicleable_id: 1, name: "BL96", ...">]>


>> vehicle = Vehicle.find(3)
#<Vehicle id: 3, vehicleable_type: "Car", vehicleable_id: 2, name: "TS78Z", mileage: 89, created_at: ...">

# check whether a Vehicle is a Car or Motorcycle
>> vehicle.car?  #=> true
>> vehicle.motorcylce? #=> false

# get vehicleable
>> vehicle.car # <Car id: 1, adjustable_roof: true, ...>
>> vehicle.motorcycle # nil
```

So, `delegated_type` can be thought of as sugar on top of polymorphic relations
that adds convenience methods.

Check out the [pull request](https://github.com/rails/rails/pull/39341/files) to
learn more.

## Links

- [Human page](https://www.bigbinary.com/blog/rails-6-1-adds-delegated-type-to-active-record)
