rubyonrails.org에서 더 보기:

GitHub에서 이 파일을 읽지 마세요. 가이드는 https://guides.rubyonrails.org 에서 제공됩니다.

Active Record 기초

이 가이드는 Active Record에 대한 소개입니다.

이 가이드를 읽고 나면 다음을 알 수 있습니다:

  • Active Record가 Model-View-Controller (MVC) 패러다임에 어떻게 부합하는지
  • Object Relational Mapping과 Active Record 패턴이 무엇이고 Rails에서 어떻게 사용되는지
  • 관계형 데이터베이스에 저장된 데이터를 조작하기 위해 Active Record 모델을 사용하는 방법
  • Active Record 스키마 명명 규칙
  • 데이터베이스 마이그레이션, 유효성 검사, 콜백, 그리고 관계의 개념

1 Active Record란 무엇인가?

Active Record는 MVC의 M - 모델 - 의 일부로, 데이터와 비즈니스 로직을 표현하는 시스템 계층입니다. Active Record는 데이터베이스에 영구 저장이 필요한 속성을 가진 Ruby 객체를 생성하고 사용하는 것을 도와줍니다.

참고: Active Record와 Active Model의 차이점은 무엇일까요? 데이터베이스 지원이 필요하지 않은 Ruby 객체로 데이터를 모델링하는 것이 가능합니다. Rails에서는 이를 위해 Active Model을 일반적으로 사용하며, Active Record와 Active Model 모두 MVC의 M의 일부이며, 순수 Ruby 객체도 마찬가지입니다.

"Active Record"라는 용어는 소프트웨어 아키텍처 패턴을 지칭하기도 합니다. Rails의 Active Record는 이 패턴의 구현체입니다. 또한 Object Relational Mapping 시스템이라고 불리는 것에 대한 설명이기도 합니다. 아래 섹션에서 이러한 용어들을 설명합니다.

1.1 The Active Record Pattern

Active Record 패턴은 Martin Fowler가 Patterns of Enterprise Application Architecture 책에서 "데이터베이스 테이블의 행을 래핑하고, 데이터베이스 접근을 캡슐화하며, 해당 데이터에 도메인 로직을 추가하는 객체"라고 설명했습니다. Active Record 객체는 데이터와 동작을 모두 가지고 있습니다. Active Record 클래스는 기반이 되는 데이터베이스의 레코드 구조와 매우 밀접하게 일치합니다. 이러한 방식으로 사용자는 아래 예제에서 보게 될 것처럼 데이터베이스에서 쉽게 읽고 쓸 수 있습니다.

1.2 Object Relational Mapping

Object Relational Mapping(일반적으로 ORM이라고 함)은 프로그래밍 언어의 풍부한 객체를 관계형 데이터베이스 관리 시스템(RDBMS)의 테이블에 연결하는 기술입니다. Rails 애플리케이션의 경우 이는 Ruby 객체입니다. ORM을 사용하면 Ruby 객체의 속성과 객체 간의 관계를 SQL 문을 직접 작성하지 않고도 데이터베이스에 쉽게 저장하고 검색할 수 있습니다. 전반적으로 ORM은 작성해야 하는 데이터베이스 접근 코드의 양을 최소화합니다.

Active Record를 완전히 이해하기 위해서는 관계형 데이터베이스 관리 시스템(RDBMS)과 구조화 질의 언어(SQL)에 대한 기본 지식이 도움이 됩니다. 더 자세히 알고 싶다면 이 SQL 튜토리얼(또는 이 RDBMS 튜토리얼)을 참조하거나 다른 방법으로 공부해보세요.

1.3 ORM Framework로서의 Active Record

Active Record는 Ruby 객체를 사용하여 다음과 같은 작업을 할 수 있게 해줍니다:

  • 모델과 해당 데이터를 표현합니다.
  • 모델 간의 관계를 표현합니다.
  • 관련 모델을 통해 상속 계층을 표현합니다.
  • 데이터베이스에 저장되기 전에 모델을 검증합니다.
  • 객체 지향적인 방식으로 데이터베이스 작업을 수행합니다.

2 Active Record의 설정보다 관례

다른 프로그래밍 언어나 프레임워크를 사용하여 애플리케이션을 작성할 때는 많은 설정 코드를 작성해야 할 수 있습니다. 이는 특히 ORM 프레임워크 전반에 해당합니다. 하지만 Rails가 채택한 관례를 따르면, Active Record 모델을 만들 때 설정 코드를 거의 또는 전혀 작성하지 않아도 됩니다.

Rails는 대부분의 경우 애플리케이션을 같은 방식으로 구성한다면, 그 방식이 기본값이 되어야 한다는 아이디어를 채택합니다. 명시적인 설정은 관례를 따를 수 없는 경우에만 필요해야 합니다.

Active Record에서 설정보다 관례를 활용하기 위해서는 몇 가지 명명 및 스키마 관례를 따라야 합니다. 그리고 필요한 경우, 명명 관례를 재정의하는 것도 가능합니다.

2.1 명명 규칙

Active Record는 모델(Ruby 객체로 표현됨)과 데이터베이스 테이블 간의 매핑을 위해 다음과 같은 명명 규칙을 사용합니다:

Rails는 모델의 클래스 이름을 복수형으로 만들어 해당하는 데이터베이스 테이블을 찾습니다. 예를 들어, Book이라는 클래스는 books라는 데이터베이스 테이블에 매핑됩니다. Rails의 복수화 메커니즘은 매우 강력하며 영어의 규칙적인 단어와 불규칙적인 단어 모두를 복수형(및 단수형)으로 변환할 수 있습니다. 이는 Active Supportpluralize 메서드를 사용합니다.

두 단어 이상으로 구성된 클래스 이름의 경우, 모델 클래스 이름은 Ruby의 UpperCamelCase 이름 규칙을 따릅니다. 이 경우 데이터베이스 테이블 이름은 snake_case 이름이 됩니다. 예를 들면:

  • BookClub은 모델 클래스로, 단수형이며 각 단어의 첫 글자가 대문자입니다.
  • book_clubs는 매칭되는 데이터베이스 테이블로, 복수형이며 단어 사이를 밑줄로 구분합니다.

다음은 모델 클래스 이름과 해당하는 테이블 이름의 추가 예시입니다:

모델 / 클래스 테이블 / 스키마
Article articles
LineItem line_items
Product products
Person people

2.2 Schema 규칙

Active Record는 데이터베이스 테이블의 컬럼명에 대해서도 컬럼의 목적에 따라 규칙을 사용합니다.

  • Primary keys - 기본적으로 Active Record는 테이블의 primary key로 id라는 이름의 정수형 컬럼을 사용합니다(PostgreSQL, MySQL, MariaDB의 경우 bigint, SQLite의 경우 integer). Active Record Migrations를 사용해 테이블을 생성할 때 이 컬럼은 자동으로 생성됩니다.
  • Foreign keys - 이러한 필드들은 singularized_table_name_id 패턴을 따라 이름이 지어져야 합니다(예: order_id, line_item_id). Active Record는 모델 간의 관계를 생성할 때 이러한 필드들을 찾습니다.

Active Record 인스턴스에 추가 기능을 제공하는 몇 가지 선택적 컬럼명도 있습니다:

  • created_at - 레코드가 처음 생성될 때 현재 날짜와 시간으로 자동 설정됩니다.
  • updated_at - 레코드가 생성되거나 업데이트될 때마다 현재 날짜와 시간으로 자동 설정됩니다.
  • lock_version - 모델에 optimistic locking을 추가합니다.
  • type - 모델이 Single Table Inheritance를 사용함을 지정합니다.
  • (association_name)_type - polymorphic associations의 타입을 저장합니다.
  • (table_name)_count - 관계된 객체들의 수를 캐시하는데 사용됩니다. 예를 들어, Article이 많은 Comment를 가지고 있다면, articles 테이블의 comments_count 컬럼은 각 article에 대한 기존 comment의 수를 캐시합니다.

이러한 컬럼명들은 선택사항이지만 Active Record에서 예약되어 있습니다. 테이블의 컬럼 이름을 지을 때 예약어 사용을 피하세요. 예를 들어, type은 Single Table Inheritance(STI)를 사용하는 테이블을 지정하는 데 사용되는 예약어입니다. STI를 사용하지 않는다면, 모델링하는 데이터를 정확하게 설명하는 다른 단어를 사용하세요.

3 Active Record 모델 생성하기

Rails 애플리케이션을 생성할 때, 추상 ApplicationRecord 클래스가 app/models/application_record.rb에 생성됩니다. ApplicationRecord 클래스는 ActiveRecord::Base를 상속받으며, 이는 일반 Ruby 클래스를 Active Record 모델로 변환합니다.

ApplicationRecord는 앱의 모든 Active Record 모델의 기본 클래스입니다. 새로운 모델을 만들려면 ApplicationRecord 클래스를 상속받으면 됩니다.

Rails가이드 문서 내용을 먼저 공유해주셔야 번역을 시작할 수 있습니다. 번역할 내용을 제공해주시면 요청하신 대로 기술 용어는 영어로 유지하고 마크다운 문법과 링크는 그대로 유지하면서 한국어로 번역해드리겠습니다.

class Book < ApplicationRecord
end

이는 데이터베이스의 books 테이블에 매핑되는 Book 모델을 생성하며, 테이블의 각 컬럼은 Book 클래스의 속성에 매핑됩니다. Book 인스턴스는 books 테이블의 한 행을 나타낼 수 있습니다. id, title, author 컬럼이 있는 books 테이블은 다음과 같은 SQL문을 사용하여 생성할 수 있습니다:

CREATE TABLE books (
  id int(11) NOT NULL auto_increment,
  title varchar(255),
  author varchar(255),
  PRIMARY KEY  (id)
);

하지만 이는 Rails에서 일반적으로 하는 방법이 아닙니다. Rails에서 데이터베이스 테이블은 일반적으로 SQL을 직접 사용하지 않고 Active Record Migrations을 사용하여 생성됩니다. 위의 books 테이블을 위한 migration은 다음과 같이 생성할 수 있습니다:

$ bin/rails generate migration CreateBooks title:string author:string

그리고 다음과 같이 됩니다:

# 참고:
# primary key로서의 `id` 컬럼은 규칙에 따라 자동으로 생성됩니다.
# `created_at`과 `updated_at` 컬럼은 `t.timestamps`에 의해 추가됩니다.

# db/migrate/20240220143807_create_books.rb
class CreateBooks < ActiveRecord::Migration[8.1]
  def change
    create_table :books do |t|
      t.string :title
      t.string :author

      t.timestamps
    end
  end
end

해당 migration은 id, title, author, created_at, updated_at 컬럼을 생성합니다. 이 테이블의 각 row는 동일한 속성(id, title, author, created_at, updated_at)을 가진 Book 클래스의 인스턴스로 표현될 수 있습니다. 다음과 같이 book의 속성에 접근할 수 있습니다:

irb> book = Book.new
=> #<Book:0x00007fbdf5e9a038 id: nil, title: nil, author: nil, created_at: nil, updated_at: nil>

irb> book.title = "The Hobbit" # title 속성에 "The Hobbit"을 할당
=> "The Hobbit"
irb> book.title # title 속성값을 읽어옴
=> "The Hobbit"

명령어 bin/rails generate model Book title:string author:string를 사용하여 Active Record 모델 클래스와 그에 맞는 migration을 생성할 수 있습니다. 이는 app/models/book.rb, db/migrate/20240220143807_create_books.rb 파일과 테스트 목적의 몇 가지 다른 파일들을 생성합니다.

3.1 Namespaced Model 생성하기

Active Record model은 기본적으로 app/models 디렉토리 아래에 위치합니다. 하지만 유사한 model들을 고유한 폴더와 namespace 아래에 배치하여 model들을 구성하고 싶을 수 있습니다. 예를 들어, Book::OrderBook::Review 클래스명을 가진 order.rbreview.rbapp/models/book 아래에 배치하는 것입니다. Active Record를 사용하여 namespaced model을 생성할 수 있습니다.

Book module이 아직 존재하지 않는 경우, generate 명령어는 다음과 같이 모든 것을 생성합니다:

$ bin/rails generate model Book::Order
      invoke  active_record  
      create    db/migrate/20240306194227_create_book_orders.rb
      create    app/models/book/order.rb
      create    app/models/book.rb
      invoke    test_unit
      create      test/models/book/order_test.rb
      create      test/fixtures/book/orders.yml

Book 모듈이 이미 존재하는 경우, 충돌을 해결하라는 메시지가 표시됩니다:

$ bin/rails generate model Book::Order
      invoke  active_record
      create    db/migrate/20240305140356_create_book_orders.rb
      create    app/models/book/order.rb
    conflict    app/models/book.rb
  /Users/bhumi/Code/rails_guides/app/models/book.rb를 덮어쓰시겠습니까? (도움말을 보려면 "h"를 입력하세요) [Ynaqdhm]

네임스페이스가 있는 모델 생성이 완료되면 BookOrder 클래스는 다음과 같이 생성됩니다:

# app/models/book.rb 
module Book
  def self.table_name_prefix
    "book_"
  end 
end

# app/models/book/order.rb
class Book::Order < ApplicationRecord
end

이 예시에서는 Book 모듈 내에 Book::Order 모델이 정의됩니다. table_name_prefix 메서드는 해당 모듈 내의 모든 모델의 테이블 이름 앞에 "book_" 접두사를 추가합니다. 이렇게 하면 테이블 이름이 "book_orders"가 됩니다.

Book에서 table_name_prefix를 설정하면 Order 모델의 데이터베이스 테이블 이름을 단순히 orders가 아닌 book_orders로 지정할 수 있습니다.

또 다른 가능성은 app/models에 이미 유지하고 싶은 Book 모델이 있는 경우입니다. 이 경우 generate 명령 중에 n을 선택하여 book.rb를 덮어쓰지 않도록 할 수 있습니다.

이렇게 하면 table_name_prefix가 필요 없이도 Book::Order 클래스에 대해 네임스페이스가 지정된 테이블 이름을 사용할 수 있습니다.

# app/models/book.rb
class Book < ApplicationRecord
  # 기존 코드 
end

Book::Order.table_name
# => "book_orders"

4 명명 규칙 오버라이딩하기

서로 다른 명명 규칙을 따라야 하거나 레거시 데이터베이스에서 Rails 애플리케이션을 사용해야 하는 경우에는 어떻게 해야 할까요? 걱정하지 마세요. 기본 규칙을 쉽게 오버라이딩할 수 있습니다.

ApplicationRecordActiveRecord::Base를 상속받기 때문에, 애플리케이션의 모델들은 다수의 유용한 메소드를 사용할 수 있습니다. 예를 들어, 사용해야 하는 테이블 이름을 커스터마이징하기 위해 ActiveRecord::Base.table_name= 메소드를 사용할 수 있습니다:

class Book < ApplicationRecord
  self.table_name = "my_books"
end

model 이름과 다른 테이블 이름을 사용하고 싶다면, self.table_name을 통해 테이블 이름을 직접 설정할 수 있습니다.

만약 그렇게 하면, fixture를 가지고 있는 클래스 이름을 (my_books.yml) 테스트 정의에서 set_fixture_class 메서드를 사용하여 수동으로 정의해야 합니다:

# test/models/book_test.rb
class BookTest < ActiveSupport::TestCase
  set_fixture_class my_books: Book
  fixtures :my_books
  # ...
end

ActiveRecord::Base.primary_key= 메서드를 사용하여 테이블의 primary key로 사용되어야 하는 컬럼을 재정의하는 것도 가능합니다:

class Book < ApplicationRecord
  self.primary_key = "book_id" # primary key를 'book_id'로 설정합니다
end

Active Record는 기본 키가 아닌 컬럼을 id라는 이름으로 사용하는 것을 권장하지 않습니다. 단일 컬럼 기본 키가 아닌 id라는 이름의 컬럼을 사용하면 해당 컬럼 값에 접근하는 것이 복잡해집니다. 애플리케이션은 기본 키가 아닌 id 컬럼의 값에 접근하기 위해 id_value 별칭 속성을 사용해야 합니다.

기본 키가 아닌 id라는 이름의 컬럼을 생성하려고 하면, Rails는 다음과 같은 오류를 마이그레이션 중에 발생시킵니다: you can't redefine the primary key column 'id' on 'my_books'. To define a custom primary key, pass { id: false } to create_table.

5 CRUD: 데이터 읽기와 쓰기

CRUD는 데이터를 조작하는 데 사용되는 네 가지 동사의 약자입니다: Create(생성), Read(읽기), Update(갱신), Delete(삭제). Active Record는 애플리케이션의 데이터베이스 테이블에 저장된 데이터를 읽고 조작할 수 있는 메서드를 자동으로 생성합니다.

Active Record는 데이터베이스 접근 세부사항을 추상화하는 이러한 고수준 메서드를 사용하여 CRUD 작업을 원활하게 수행할 수 있게 합니다. 이러한 편리한 메서드들은 모두 기본 데이터베이스에 대해 실행되는 SQL 문으로 변환된다는 점에 유의하세요.

아래 예제는 CRUD 메서드들과 그에 따른 SQL 문을 보여줍니다.

5.1 Create

Active Record 객체는 hash나 block으로부터 생성될 수 있으며, 생성 후 속성을 수동으로 설정할 수도 있습니다. new 메소드는 새로운, 저장되지 않은 객체를 반환하며, create는 객체를 데이터베이스에 저장하고 반환합니다.

예를 들어, titleauthor 속성을 가진 Book 모델이 있다고 할 때, create 메소드 호출은 객체를 생성하고 새로운 레코드를 데이터베이스에 저장할 것입니다:

book = Book.create(title: "The Lord of the Rings", author: "J.R.R. Tolkien")

# 이 레코드가 데이터베이스에 커밋될 때 `id`가 할당되는 것에 주목하세요.
book.inspect
# => "#<Book id: 106, title: \"The Lord of the Rings\", author: \"J.R.R. Tolkien\", created_at: \"2024-03-04 19:15:58.033967000 +0000\", updated_at: \"2024-03-04 19:15:58.033967000 +0000\">"

new 메서드는 객체를 생성만 할 뿐, database에 저장하지는 않습니다:

book = Book.new
book.title = "The Hobbit"
book.author = "J.R.R. Tolkien"

# 이 객체의 `id`는 아직 설정되지 않았습니다.
book.inspect
# => "#<Book id: nil, title: \"The Hobbit\", author: \"J.R.R. Tolkien\", created_at: nil, updated_at: nil>"

# 위의 `book`은 아직 데이터베이스에 저장되지 않았습니다.

book.save
book.id # => 107

# 이제 `book` 레코드가 데이터베이스에 커밋되었고 `id`를 가지게 되었습니다.

마지막으로, block이 제공되면 createnew 모두 초기화를 위해 새로운 객체를 해당 block에 yield하지만, create만이 결과 객체를 데이터베이스에 저장합니다:

book = Book.new do |b|
  b.title = "Metaprogramming Ruby 2"
  b.author = "Paolo Perrotta"
end

book.save

블록을 사용하여 object를 생성하고 초기화했습니다. block의 실행이 끝나면 object는 자동으로 저장됩니다.

book.saveBook.create의 결과로 생성되는 SQL 문은 다음과 같습니다:

/* `created_at`과 `updated_at`은 자동으로 설정됩니다. */

INSERT INTO "books" ("title", "author", "created_at", "updated_at") VALUES (?, ?, ?, ?) RETURNING "id"  [["title", "Metaprogramming Ruby 2"], ["author", "Paolo Perrotta"], ["created_at", "2024-02-22 20:01:18.469952"], ["updated_at", "2024-02-22 20:01:18.469952"]]

Active Record는 데이터베이스에서 데이터에 접근하기 위한 풍부한 API를 제공합니다. 단일 레코드나 여러 레코드를 조회하고, 어떤 속성으로든 필터링하고, 정렬하고, 그룹화하고, 특정 필드를 선택할 수 있으며, SQL로 할 수 있는 모든 것을 수행할 수 있습니다.

# 모든 book들의 컬렉션을 반환합니다.
books = Book.all

# 단일 book을 반환합니다.
first_book = Book.first
last_book = Book.last
book = Book.take

위 코드는 다음과 같은 SQL을 생성합니다:

-- Book.all "books" 테이블의 모든 컬럼을 조회합니다

-- Book.first "books" 테이블의 모든 컬럼을 "books"."id" 기준 오름차순으로 정렬하여 첫 번째 레코드를 조회합니다

-- Book.last "books" 테이블의 모든 컬럼을 "books"."id" 기준 내림차순으로 정렬하여 첫 번째 레코드를 조회합니다

-- Book.take "books" 테이블의 모든 컬럼 중 첫 번째 레코드를 조회합니다

find_bywhere를 사용해 특정 책들을 찾을 수도 있습니다. find_by가 단일 레코드를 반환하는 반면, where는 레코드의 리스트를 반환합니다:

# 주어진 title을 가진 첫 번째 book을 반환하거나, book이 없으면 `nil`을 반환합니다.
book = Book.find_by(title: "Metaprogramming Ruby 2")

# Book.find_by(id: 42)의 대안입니다. 일치하는 book이 없으면 exception을 발생시킵니다.
book = Book.find(42)

위 코드는 다음과 같은 SQL을 생성합니다:

-- 제목이 "Metaprogramming Ruby 2"인 Book을 찾는 쿼리 
SELECT "books".* FROM "books" WHERE "books"."title" = ? LIMIT ?  [["title", "Metaprogramming Ruby 2"], ["LIMIT", 1]]

-- id가 42인 Book을 찾는 쿼리
SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ?  [["id", 42], ["LIMIT", 1]]
# 특정 작가의 모든 책을 찾고, created_at을 기준으로 내림차순 정렬합니다.
Book.where(author: "Douglas Adams").order(created_at: :desc)

다음 SQL이 만들어집니다:

SELECT "books".* FROM "books" WHERE "books"."author" = ? ORDER BY "books"."created_at" DESC [["author", "Douglas Adams"]]

Active Record에는 레코드를 읽고 조회하는 더 많은 메서드들이 있습니다. 이에 대해서는 Active Record Query 가이드에서 자세히 알아볼 수 있습니다.

5.2 Update

Active Record 객체가 검색되면 그 객체의 attribute들을 수정할 수 있고 데이터베이스에 저장할 수 있습니다.

book = Book.find_by(title: "The Lord of the Rings") 
book.title = "The Lord of the Rings: The Fellowship of the Ring"
book.save

title이 "The Lord of the Rings"인 Book을 찾아서 title을 "The Lord of the Rings: The Fellowship of the Ring"으로 변경하고 저장합니다.

이를 위한 단축 표현은 속성 이름을 원하는 값으로 매핑하는 hash를 사용하는 것입니다. 다음과 같이 작성할 수 있습니다:

book = Book.find_by(title: "The Lord of the Rings")
book.update(title: "The Lord of the Rings: The Fellowship of the Ring")

title이 "The Lord of the Rings"인 Book을 찾아서 해당 book의 title을 "The Lord of the Rings: The Fellowship of the Ring"으로 업데이트합니다.

update는 다음과 같은 SQL을 발생시킵니다:

/* `updated_at`이 자동으로 설정됩니다. */

 UPDATE "books" SET "title" = ?, "updated_at" = ? WHERE "books"."id" = ?  [["title", "The Lord of the Rings: The Fellowship of the Ring"], ["updated_at", "2024-02-22 20:51:13.487064"], ["id", 104]]

여러 attribute를 한 번에 업데이트할 때 유용합니다. create와 유사하게 update를 사용하면 업데이트된 레코드들이 데이터베이스에 commit됩니다.

만약 callback이나 validation 없이 여러 레코드를 일괄적으로 업데이트하고 싶다면, update_all을 사용하여 데이터베이스를 직접 업데이트할 수 있습니다:

Book.update_all(status: "already own")

여러 레코드의 status를 한번에 "already own"으로 업데이트합니다.

5.3 Delete

마찬가지로, 한 번 조회된 Active Record 객체는 삭제될 수 있으며, 이는 해당 객체를 데이터베이스에서 제거합니다.

book = Book.find_by(title: "The Lord of the Rings")
book.destroy

title 속성이 "The Lord of the Rings"인 Book을 찾아서 해당 레코드를 삭제합니다.

destroy는 다음의 SQL을 실행합니다:

"books"에서 "books"."id" = ? 값을 삭제 [["id", 104]]

여러 레코드를 한 번에 삭제하려면 destroy_by 또는 destroy_all 메소드를 사용할 수 있습니다:

# Douglas Adams가 쓴 모든 책을 찾아서 삭제합니다.  
Book.destroy_by(author: "Douglas Adams")

# 모든 책을 삭제합니다.
Book.destroy_all

6 Validations

Active Record는 모델이 데이터베이스에 저장되기 전에 모델의 상태를 검증할 수 있게 해줍니다. 다양한 유형의 검증을 할 수 있는 여러 메서드들이 있습니다. 예를 들어, 속성 값이 비어있지 않은지, 고유한지, 이미 데이터베이스에 존재하지 않는지, 특정 형식을 따르는지 등 많은 검증이 가능합니다.

save, create, update와 같은 메서드들은 모델을 데이터베이스에 저장하기 전에 검증을 수행합니다. 모델이 유효하지 않으면 데이터베이스 작업이 수행되지 않습니다. 이 경우 saveupdate 메서드는 false를 반환합니다. create 메서드는 여전히 객체를 반환하며, 이를 통해 오류를 확인할 수 있습니다. 이러한 모든 메서드들은 bang 버전(즉, save!, create!, update!)을 가지고 있으며, 이들은 검증이 실패했을 때 ActiveRecord::RecordInvalid 예외를 발생시키는 더 엄격한 메서드입니다. 다음은 이를 설명하는 간단한 예시입니다:

class User < ApplicationRecord
  validates :name, presence: true
end
irb> user = User.new
irb> user.save 
=> false
irb> user.save!
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank (유효성 검사 실패: Name은 비어있을 수 없습니다)

create 메서드는 유효성 여부에 관계없이 항상 model을 반환합니다. 이후 해당 model에서 발생한 오류를 검사할 수 있습니다.

irb> user = User.create
=> #<User:0x000000013e8b5008 id: nil, name: nil>
irb> user.errors.full_messages
=> ["Name은 비어있을 수 없습니다"]

Active Record Validations 가이드에서 validations에 대해 더 자세히 알아볼 수 있습니다.

7 Callbacks

Active Record callbacks를 사용하면 모델의 생명주기에서 특정 이벤트에 코드를 연결할 수 있습니다. 이를 통해 새로운 레코드를 생성하거나, 업데이트하거나, 삭제하는 등의 이벤트가 발생할 때 코드를 실행하여 모델에 동작을 추가할 수 있습니다.

class User < ApplicationRecord
  after_create :log_new_user

  private
    def log_new_user
      puts "새로운 사용자가 등록되었습니다"
    end
end
irb> @user = User.create
새로운 user가 등록되었습니다

Rails는 migrations를 통해 데이터베이스 스키마 변경을 관리하는 편리한 방법을 제공합니다. Migrations은 도메인 특화 언어로 작성되며 파일에 저장되어 Active Record가 지원하는 모든 데이터베이스에 대해 실행됩니다.

콜백에 대해 더 자세히 알아보려면 Active Record Callbacks 가이드를 참고하세요.

아래는 publications라는 새로운 테이블을 생성하는 migration의 예시입니다:

class CreatePublications < ActiveRecord::Migration[8.1]
  def change
    create_table :publications do |t|
      t.string :title
      t.text :description
      t.references :publication_type
      t.references :publisher, polymorphic: true 
      t.boolean :single_issue

      t.timestamps
    end
  end
end

위 코드는 데이터베이스에 독립적입니다: MySQL, MariaDB, PostgreSQL, SQLite 등에서 실행됩니다.

Rails는 어떤 migration이 데이터베이스에 적용되었는지 추적하며, 이를 동일한 데이터베이스 내의 schema_migrations라는 테이블에 저장합니다.

migration을 실행하고 테이블을 생성하려면 bin/rails db:migrate를 실행하고, 이를 롤백하고 테이블을 삭제하려면 bin/rails db:rollback을 실행합니다.

migration에 대해 더 자세히 알아보려면 Active Record Migrations 가이드를 참조하세요.

8 Associations

Active Record association을 사용하면 모델 간의 관계를 정의할 수 있습니다. Association은 일대일, 일대다, 다대다 관계를 설명하는 데 사용될 수 있습니다. 예를 들어, "Author가 여러 Book을 가진다"와 같은 관계는 다음과 같이 정의할 수 있습니다:

class Author < ApplicationRecord
  has_many :books
end

Author 클래스는 이제 작가에게 책을 추가하고 제거할 수 있는 메서드와 더 많은 기능을 가지게 되었습니다.

association에 대해서는 Active Record Associations 가이드에서 더 자세히 알아볼 수 있습니다.



맨 위로