단일 테이블 상속 (Single Table Inheritance, STI)

단일 테이블 상속이란 관계형 데이터베이스에서 객체 지향 프로그래밍의 상속이라는 개념을 사용하기 위한 방법이다. 하나의 테이블에 기본 모델을 상속하는 여러 모델들의 데이터를 저장하고, 테이블의 특정 컬럼을 해당 데이터와 연결될 모델을 구분하기 위해 사용한다.

Active Record의 CoC (Convention over Configuration)

Rails(Active Record)에서는 모델이 단일 테이블 상속을 사용하는 경우, type 컬럼을 모델 식별을 위해 사용하는 것이 관례이다.

예를 들어, User 모델을 상속하는 WriterReader 가 있고, 우리가 STI를 사용하려 한다면, User 모델의 마이그레이션은 type 컬럼을 포함해야 한다.

1
2
3
4
5
6
7
8
9
10
class CreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
t.string :email
t.string :password_digest
t.string :type # STI에 사용될 컬럼
t.timestamps
end
end
end

STI 사용하기

이제 User 모델을 상속받는 Writer, Reader 모델을 만들어보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class User < ApplicationRecord
...
end

class Writer < User
has_many :novels
before_destroy :can_leave?, prepend: true

def can_leave?
if novels.count > 0
errors[:base] << '연재중인 소설이 있어서 탈퇴할 수 없습니다.'
throw :abort
end

true
end
end

class Reader < User
has_many :payments
end

둘 다 User의 속성과 함수를 가지지만, Reader 는 탈퇴 조건이 따로 없는 반면, Writer 의 경우 연재중인 소설이 있는 경우에는 탈퇴할 수 없도록 설정되어 있다. WriterReader 모델은 따로 테이블을 가지지 않고, User 테이블에 type: 'Writer' 혹은 type: Reader 로 저장된다.
생성은 User#create 혹은 Reader#create 로 가능하다. User#create 로 생성하는 경우 type 을 명시해야 한다.

1
2
User.create(email: 'mu29@yeoubi.net', password: '1234', type: 'Reader')
Reader.create(email: 'mu29@yeoubi.net', password: '1234')

STI 관련 이슈

이러한 Rails의 STI에 관한 관례를 알지 못하고 type 컬럼을 사용하면 아래와 같은 오류가 발생하게 된다.

1
2
LoadError:
Unable to autoload constant Writer, expected /Users/injung/Github/ssm-api/app/models/writer.rb to define it

type 컬럼은 쓰고 싶지만, STI를 쓰고 싶지 않다면 해당 설정을 비활성화 할 수 있다.

1
2
3
class User < ApplicationRecord
self.inheritance_column = :_type_disabled
end

Comment and share

  • page 1 of 1

InJung Chung

author.bio


CTO @tenb


Seoul, Korea