ruby
47 lines · 8 steps
How STI models share behavior in Rails
A single Employee table backs four classes that inherit validations and override pay logic through single-table inheritance.
Explained by
highlit
1class Employee < ApplicationRecord
2 validates :name, presence: true
3 validates :salary, numericality: { greater_than: 0 }
4
5 scope :managers, -> { where(type: "Manager") }
6 scope :engineers, -> { where(type: "Engineer") }
7
8 def weekly_pay
9 (salary / 52.0).round(2)
10 end
11
12 def role
13 type&.underscore&.humanize || "Employee"
14 end
15end
16
17class Manager < Employee
18 has_many :reports, class_name: "Employee", foreign_key: :manager_id
19
20 def weekly_pay
21 super + bonus_share
22 end
23
24 def bonus_share
25 (annual_bonus.to_f / 52.0).round(2)
26 end
27end
28
29class Engineer < Employee
30 validates :primary_language, presence: true
31
32 def weekly_pay
33 super + on_call_stipend
34 end
35
36 def on_call_stipend
37 on_call? ? 200.0 : 0.0
38 end
39end
40
41class Contractor < Employee
42 validates :hourly_rate, numericality: { greater_than: 0 }
43
44 def weekly_pay
45 (hourly_rate * hours_per_week).round(2)
46 end
47end
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Single-table inheritance lets subclasses share one table while specializing behavior through Ruby's normal class hierarchy.
- 2Calling super in an overridden method composes subclass-specific additions on top of the base implementation instead of replacing it.
- 3Validations and scopes defined on the base model apply to every subclass, while subclasses can add their own constraints.
Related explainers
ruby
class ToastBroadcaster include ActionView::RecordIdentifier def self.broadcast_to(user, message:, type: :notice)
How Turbo Stream toasts broadcast in Rails
turbo-streams
service-object
real-time
Intermediate
6 steps
ruby
class TemplateInterpolator PLACEHOLDER = /\{\{\s*([\w.]+)\s*\}\}/ def initialize(strict: false)
Interpolating templates with dotted keys in Ruby
regex
string-interpolation
hash-traversal
Intermediate
6 steps
ruby
class KeyTransformer def self.camelize(data) new.camelize(data) end
Recursively camelizing nested Ruby data
recursion
data-transformation
pattern-matching
Intermediate
7 steps
ruby
module Paginatable extend ActiveSupport::Concern private
A reusable pagination concern in Rails
pagination
concerns
http-headers
Intermediate
8 steps
ruby
class Api::MessagesController < ApiController before_action :authenticate_api_key! rate_limit to: 100,
Layered API rate limiting in Rails
rate-limiting
api-authentication
throttling
Intermediate
9 steps
ruby
class Order < ApplicationRecord include AASM belongs_to :warehouse
Modeling an order lifecycle with AASM in Rails
state machine
guards
callbacks
Intermediate
10 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-sti-models-share-behavior-in-rails-explained-ruby-2d08/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.