Active Model 기초 — 데이터베이스 없이도 동작하는 모델

Active Model 기초 — 데이터베이스 없이도 동작하는 모델

Active Record가 데이터베이스와 붙어 있는 모델이라면, "데이터베이스는 안 쓰고 싶지만 Rails의 뷰·콘트롤러와는 이어지고 싶다"는 상황엔 뭘 쓸까요? 바로 Active Model이 그 역할을 해요. Active Model은 모델로 동작하기 위한 최소한의 인터페이스를 제공해서, 평범한 루비 객체도 Active Record처럼 유효성 검사·이름 규칙·직렬화 등을 갖추게 해줘요. DB 저장이 필요 없는 폼 객체나 값 객체를 만들 때 특히 유용해요.

출처: Active Model Basics

본문

Active Model이 해주는 일

Active Model은 모델이 갖추어야 할 공통 기능을 제공해요. 액션팩(Action Pack)과 함께 쓰이는 평범한 루비 객체가 되도록 돕고, Rails 밖에서도 쓸 수 있는 커스텀 ORM을 만드는 기반이 되어요.

  • 유효성 검사를 위한 Validations
  • 이름 규칙 변환을 위한 Naming
  • 직렬화를 위한 Serialization
  • 문자열을 라벨로 바꿔주는 Translation

이 기능들이 모여 Active Record 같은 ORM이 아닌 객체에도 "모델답게" 동작할 힘을 줘요.

액션팩과 함께 쓰기: 폼 객체

가장 흔한 용도는 폼 객체예요. 예를 들어 회원가입 폼이 사용자 정보와 구독 정보를 한 번에 받아야 할 때, 데이터베이스 테이블 하나로는 표현이 애매해요. 이때 Active Model 기반 클래스를 만들어 폼을 처리하고, 저장 시점에 필요한 모델로 옮겨 담으면 깔끔해요.

class SignupForm
  include ActiveModel::Model

  attr_accessor :name, :email, :subscribe

  validates :name, :email, presence: true
end

ActiveModel::Model을 include하면 new, valid?, errors 같은 모델다운 기능을 즉시 얻게 돼요. 콘트롤러에서 받은 파라미터를 넘겨 폼 객체를 만들 수 있어요.

form = SignupForm.new(params[:signup_form])
if form.valid?
  # User, Subscription 등으로 저장 처리
end

유효성 검사

ActiveModel::Validations는 객체의 상태를 검사하고 오류를 담는 API예요. 위의 presence: true처럼 검증 규칙을 선언하면 valid?가 검사를 실행하고, 실패한 항목은 errors에 모여요.

form.valid?                    # => false
form.errors[:name]             # => ["can't be blank"]

ORM과 관계없이 이 검증 체계를 쓰려면 모델에 ActiveModel::Validations를 include하면 돼요.

이름 규칙 (Naming)

ActiveModel::Naming은 모델 클래스 이름을 다양한 형태로 변환해줘요. 라우트·뷰 헬퍼가 쓰는 이름 규칙을 제공해, 커스텀 클래스도 Rails 컨벤션에 자연스럽게 맞춰줘요.

class SignupForm
  include ActiveModel::Model
end

SignupForm.model_name.name        # => "SignupForm"
SignupForm.model_name.human       # => "Signup form"
SignupForm.model_name.route_key   # => "signup_forms"

route_key 같은 값이 라우팅과 파라미터 키에 그대로 쓰여서, 커스텀 모델도 표준 리소스처럼 다뤄질 수 있어요.

직렬화 (Serialization)

객체를 JSON처럼 전송 가능한 형태로 만들 때 ActiveModel::Serialization을 써요. 폼 객체를 API 응답으로 만들거나, 디버그 출력을 할 때 유용해요.

class SignupForm
  include ActiveModel::Model
  include ActiveModel::Serialization

  attr_accessor :name, :email
end

form = SignupForm.new(name: "지민", email: "[email protected]")
form.serializable_hash    # => {"name" => "지민", "email" => "[email protected]"}

커스텀 ORM의 기반

Active Model은 Rails에 묶여 있지 않아서, 다른 ORM을 만들거나 Rails 밖에서 쓰는 것도 가능해요. ActiveModel::API, ActiveModel::Validations, ActiveModel::Naming 같은 모듈을 원하는 대로 조합해서 자신만의 모델 계층을 설계할 수 있어요. 데이터베이스 영속이 필요 없는 도메인 객체를 다룰 때, Active Record의 무게 없이 이 방식을 선택하는 경우가 많아요.

더 알아보기 (Learn more)