액티브 레코드 기본

이 가이드는 액티브 레코드에 대한 소개입니다.

이 가이드를 읽고 나면 다음을 알게 될 것입니다:

  • 액티브 레코드가 모델-뷰-컨트롤러(MVC) 패러다임에 어떻게 적합하는지.
  • 객체 관계형 매핑(ORM)과 액티브 레코드 패턴이 무엇이며 Rails에서 어떻게 사용되는지.
  • 관계형 데이터베이스에 저장된 데이터를 조작하기 위해 액티브 레코드 모델을 사용하는 방법.
  • 액티브 레코드 스키마 명명 규칙.
  • 데이터베이스 마이그레이션, 유효성 검사, 콜백, 연관관계의 개념.

액티브 레코드란 무엇인가?

액티브 레코드는 MVC의 M, 즉 모델 부분을 구성합니다. 모델은 데이터와 비즈니스 로직을 나타내는 시스템의 계층입니다. 액티브 레코드는 데이터베이스에 지속적으로 저장되어야 하는 속성을 가진 루비 객체를 생성하고 사용할 수 있게 해줍니다.

참고: 액티브 레코드와 액티브 모델의 차이점은 무엇인가? 데이터베이스에 의해 뒷받침되지 않는 루비 객체로 데이터를 모델링할 수 있습니다. 액티브 모델은 Rails에서 이를 일반적으로 사용하며, 액티브 레코드와 액티브 모델 모두 MVC의 M 부분이자 자체 일반 루비 객체의 일부입니다.

“액티브 레코드"라는 용어는 또한 소프트웨어 아키텍처 패턴을 나타냅니다. Rails의 액티브 레코드는 그 패턴의 구현입니다. 또한 객체 관계형 매핑 시스템이라고도 불립니다. 아래 섹션에서 이러한 용어를 설명합니다.

액티브 레코드 패턴

마틴 파울러가 설명한 액티브 레코드 패턴은 "데이터베이스 테이블의 행을 감싸고 데이터베이스 액세스를 캡슐화하며 해당 데이터에 도메인 로직을 추가하는 객체"입니다. 액티브 레코드 객체는 데이터와 동작을 모두 가집니다. 액티브 레코드 클래스는 기본 데이터베이스의 레코드 구조와 매우 밀접하게 일치합니다. 이를 통해 사용자는 아래 예제에서 볼 수 있듯이 데이터베이스에서 쉽게 읽고 쓸 수 있습니다.

객체 관계형 매핑

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

참고: 관계형 데이터베이스 관리 시스템(RDBMS)과 구조화된 쿼리 언어(SQL)에 대한 기본 지식이 액티브 레코드를 완전히 이해하는 데 도움이 됩니다. 이 튜토리얼(또는 이 튜토리얼)을 참조하거나 다른 방법으로 더 자세히 학습하시기 바랍니다.

ORM 프레임워크로서의 액티브 레코드

액티브 레코드는 다음과 같은 기능을 제공하여 루비 객체를 사용할 수 있게 해줍니다:

  • 모델과 해당 데이터 표현.
  • 모델 간 연관관계 표현.
  • 관련 모델을 통한 상속 계층 표현.
  • 데이터베이스에 저장되기 전에 모델 유효성 검사.
  • 객체 지향 방식으로 데이터베이스 작업 수행.

액티브 레코드의 설정보다는 규약

다른 프로그래밍 언어나 프레임워크를 사용하여 애플리케이션을 작성할 때는 많은 설정 코드를 작성해야 할 수 있습니다. 이는 특히 ORM 프레임워크의 경우 그렇습니다. 그러나 Rails에서 채택한 규약을 따르면 액티브 레코드 모델을 생성할 때 거의 설정 코드를 작성할 필요가 없습니다.

Rails는 대부분의 경우 애플리케이션을 동일한 방식으로 구성하는 것이 좋다는 생각을 채택합니다. 따라서 그 방식이 기본값이 되어야 합니다. 규약을 따를 수 없는 경우에만 명시적인 구성이 필요합니다.

액티브 레코드에서 설정보다는 규약을 활용하려면 몇 가지 명명 및 스키마 규약을 따라야 합니다. 그리고 필요한 경우 명명 규약을 재정의할 수 있습니다.

명명 규약

액티브 레코드는 모델(루비 객체로 표현)과 데이터베이스 테이블 간의 매핑을 위해 다음과 같은 명명 규약을 사용합니다:

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

두 개 이상의 단어로 구성된 클래스 이름의 경우, 모델 클래스 이름은 Ruby 규약에 따라 UpperCamelCase 이름을 사용합니다. 데이터베이스 테이블 이름은 snake_case 이름이 됩니다. 예를 들어:

  • BookClub은 첫 글자가 대문자인 단일 클래스 이름입니다.
  • book_clubs는 이에 해당하는 데이터베이스 테이블 이름으로, 단어 사이에 밑줄이 있는 복수형입니다.

모델 클래스 이름과 해당 테이블 이름의 몇 가지 추가 예는 다음과 같습니다:

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

스키마 규약

액티브 레코드는 데이터베이스 테이블의 열 이름에 대해서도 규약을 사용합니다. 이러한 열의 목적에 따라 다음과 같은 규약을 따릅니다.

  • 기본 키 - 기본적으로 액티브 레코드는 id라는 이름의 정수 열을 테이블의 기본 키(PostgreSQL, MySQL, MariaDB의 bigint, SQLite의 integer)로 사용합니다. 액티브 레코드 마이그레이션을 사용하여 테이블을 생성할 때 이 열이 자동으로 생성됩니다.
  • 외래 키 - 이러한 필드는 singularized_table_name_id 패턴(예: order_id, line_item_id)을 따라야 합니다. 이는 모델 간 연관관계를 생성할 때 액티브 레코드가 찾는 필드입니다.

또한 추가 기능을 제공하는 선택적 열 이름도 있습니다:

  • created_at - 레코드가 처음 생성될 때 현재 날짜와 시간으로 자동 설정됩니다.
  • updated_at - 레코드가 생성되거나 업데이트될 때마다 현재 날짜와 시간으로 자동 설정됩니다.
  • lock_version - 모델에 낙관적 잠금을 추가합니다.
  • type - 모델이 단일 테이블 상속을 사용함을 지정합니다.
  • (association_name)_type - 다형성 연관관계의 유형을 저장합니다.
  • (table_name)_count - 연관 객체 수를 캐시합니다. 예를 들어 Article에 많은 Comment가 있는 경우, articles 테이블의 comments_count 열에 각 기사의 기존 댓글 수가 저장됩니다.

참고: 이러한 열 이름은 선택 사항이지만 액티브 레코드에 예약되어 있습니다. 데이터베이스 테이블의 열 이름을 지정할 때 예약어를 피하십시오. 예를 들어 type은 단일 테이블 상속(STI)을 나타내는 예약어입니다. STI를 사용하지 않는 경우 모델링하는 데이터를 정확하게 설명하는 다른 단어를 사용하십시오.

액티브 레코드 모델 생성하기

Rails 애플리케이션을 생성할 때 app/models/application_record.rb에 추상 ApplicationRecord 클래스가 생성됩니다. ApplicationRecord 클래스는 ActiveRecord::Base를 상속하며, 이를 통해 일반 Ruby 클래스를 액티브 레코드 모델로 만들 수 있습니다.

ApplicationRecord는 애플리케이션의 모든 액티브 레코드 모델의 기반 클래스입니다. 새 모델을 생성하려면 ApplicationRecord 클래스를 상속하면 됩니다:

class Book < ApplicationRecord
end

이렇게 하면 Book 모델이 생성되며, books 데이터베이스 테이블에 매핑됩니다. 테이블의 각 열은 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에서는 데이터베이스 테이블을 액티브 레코드 마이그레이션을 사용하여 생성하며 raw SQL을 사용하지 않습니다. 위의 books 테이블에 대한 마이그레이션은 다음과 같이 생성할 수 있습니다:

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

그리고 다음과 같은 결과를 얻습니다:

# Note:
# The `id` column, as the primary key, is automatically created by convention.
# Columns `created_at` and `updated_at` are added by `t.timestamps`.

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

      t.timestamps
    end
  end
end

이 마이그레이션은 id, title, author, created_atupdated_at 열을 생성합니다. 이 테이블의 각 행은 id, title, author, created_atupdated_at 속성을 가진 Book 클래스의 인스턴스로 표현될 수 있습니다. 다음과 같이 책의 속성에 액세스할 수 있습니다:

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

irb> book.title = "The Hobbit"
=> "The Hobbit"
irb> book.title
=> "The Hobbit"

참고: 액티브 레코드 모델 클래스와 함께 일치하는 마이그레이션을 생성할 수도 있습니다. bin/rails generate model Book title:string author:string 명령을 사용하면 app/models/book.rb, db/migrate/20240220143807_create_books.rb 파일과 테스트 목적의 몇 가지 다른 파일이 생성됩니다.

네임스페이스 모델 생성하기

액티브 레코드 모델은 기본적으로 app/models 디렉토리에 배치됩니다. 그러나 유사한 모델을 자신의 폴더와 네임스페이스에 배치하여 모델을 구성할 수 있습니다. 예를 들어 order.rbreview.rbapp/models/books 아래에 배치하고 각각 Book::OrderBook::Review 클래스 이름을 사용할 수 있습니다. 액티브 레코드로 네임스페이스 모델을 생성할 수 있습니다.

Book 모듈이 아직 존재하지 않는 경우, 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
  Overwrite /Users/bhumi/Code/rails_guides/app/models/book.rb? (enter "h" for help) [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에서 tablenameprefix를 설정하면 Order 모델의 데이터베이스 테이블 이름이 orders 대신 book_orders가 됩니다.

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

이렇게 하면 table_name_prefix를 설정할 필요 없이 Book::Order 클래스에 대한 네임스페이스 테이블 이름을 유지할 수 있습니다:

# app/models/book.rb
class Book < ApplicationRecord
  # existing code
end

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

명명 규약 재정의하기

다른 명명 규약을 따르거나 레거시 데이터베이스와 함께 Rails 애플리케이션을 사용해야 하는 경우 어떻게 해야 할까요? 문제 없습니다. 기본 규약을 쉽게 재정의할 수 있습니다.

ApplicationRecordActiveRecord::Base를 상속하므로 애플리케이션의 모델에는 많은 유용한 메서드가 있습니다. 예를 들어 ActiveRecord::Base.table_name= 메서드를 사용하여 사용해야 하는 테이블 이름을 사용자 정의할 수 있습니다:

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

이렇게 하는 경우 fixtures(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= 메서드를 사용하여 테이블의 기본 키로 사용할 열을 재정의할 수 있습니다:

class Book < ApplicationRecord
  self.primary_key = "book_id"
end

참고: 액티브 레코드는 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.

CRUD: 데이터 읽기 및 쓰기

CRUD는 데이터를 조작하는 4가지 동사인 Create, Read, Update, Delete의 약자입니다. 액티브 레코드는 자동으로 애플리케이션의 데이터베이스 테이블에 저장된 데이터를 읽고 조작할 수 있는 메서드를 생성합니다.

액티브 레코드는 데이터베이스 액세스 세부 사항을 추상화하는 고수준 메서드를 사용하여 CRUD 작업을 seamless하게 수행할 수 있게 해줍니다. 이러한 편리한 메서드는 기본 데이터베이스에 대해 실행되는 SQL 문을 생성합니다.

아래 예제는 CRUD 메서드 중 몇 가지와 그에 따른 SQL 문을 보여줍니다.

Create

액티브 레코드 객체는 해시, 블록에서 생성하거나 생성 후 속성을 수동으로 설정할 수 있습니다. new 메서드는 새로운 비영속 객체를 반환하고, create 메서드는 객체를 데이터베이스에 저장하고 반환합니다.

예를 들어 titleauthor 속성이 있는 Book 모델의 경우 create 메서드 호출은 객체를 생성하고 새 레코드를 데이터베이스에 저장합니다:

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

# Note that the `id` is assigned as this record is committed to the database.
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 메서드는 데이터베이스에 저장되지 않은 객체를 인스턴스화합니다:

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

# Note that the `id` is not set for this object.
book.inspect
# => "#<Book id: nil, title: \"The Hobbit\", author: \"J.R.R. Tolkien\", created_at: nil, updated_at: nil>"

# The above `book` is not yet saved to the database.

book.save
book.id # => 107

# Now the `book` record is committed to the database and has an `id`.

마지막으로 블록이 제공되는 경우 createnew 모두 새 객체를 해당 블록에 전달하여 초기화할 수 있으며, create만 결과 객체를 데이터베이스에 영구 저장합니다:

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

book.save

book.saveBook.create의 결과 SQL 문은 다음과 같습니다:

/* Note that `created_at` and `updated_at` are automatically set. */

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"]]

Read

액티브 레코드는 데이터베이스 내의 데이터에 액세스하기 위한 풍부한 API를 제공합니다. 단일 레코드 또는 여러 레코드를 쿼리할 수 있으며, 모든 속성으로 필터링하고, 정렬하고, 그룹화하고, 특정 필드를 선택할 수 있으며, SQL로 할 수 있는 모든 작업을 수행할 수 있습니다.

# Return a collection with all books.
books = Book.all

# Return a single book.
first_book = Book.first
last_book = Book.last
book = Book.take

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

-- Book.all
SELECT "books".* FROM "books"

-- Book.first
SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT ?  [["LIMIT", 1]]

-- Book.last
SELECT "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT ?  [["LIMIT", 1]]

-- Book.take
SELECT "books".* FROM "books" LIMIT ?  [["LIMIT", 1]]

find_bywhere를 사용하여 특정 책을 찾을 수도 있습니다. find_by는 단일 레코드를 반환하지만 where는 레코드 목록을 반환합니다:

# Returns the first book with a given title or `nil` if no book is found.
book = Book.find_by(title: "Metaprogramming Ruby 2")

# Alternative to Book.find_by(id: 42). Will throw an exception if no matching book is found.
book = Book.find(42)

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

SELECT "books".* FROM "books" WHERE "books"."author" = ? LIMIT ?  [["author계속해서 번역한 내용은 다음과 같습니다:

", "J.R.R. Tolkien"], ["LIMIT", 1]]

SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ?  [["id", 42], ["LIMIT", 1]]
# Find all books with a given an author, sort by created_at in reverse chronological order.
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 Query 가이드에서 자세히 알아볼 수 있습니다.

Update

액티브 레코드 객체를 검색한 후에는 속성을 수정하고 데이터베이스에 저장할 수 있습니다.

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

이를 위한 단축 방법은 속성 이름과 원하는 값을 매핑하는 해시를 사용하는 것입니다:

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

update는 다음과 같은 SQL을 생성합니다:

/* Note that `updated_at` is automatically set. */

 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]]

이는 여러 속성을 한 번에 업데이트할 때 유용합니다. create와 마찬가지로 update를 사용하면 업데이트된 레코드가 데이터베이스에 커밋됩니다.

콜백이나 유효성 검사 없이 여러 레코드를 일괄 업데이트하려면 update_all을 사용할 수 있습니다:

Book.update_all(status: "already own")

Delete

마찬가지로 검색된 액티브 레코드 객체는 삭제하여 데이터베이스에서 제거할 수 있습니다.

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

destroy는 다음과 같은 SQL을 생성합니다:

DELETE FROM "books" WHERE "books"."id" = ?  [["id", 104]]

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

# Find and delete all books by Douglas Adams.
Book.destroy_by(author: "Douglas Adams")

# Delete all books.
Book.destroy_all

유효성 검사

액티브 레코드를 사용하면 데이터베이스에 쓰이기 전에 모델의 상태를 검증할 수 있습니다. 다양한 유형의 유효성 검사를 허용하는 여러 메서드가 있습니다. 예를 들어 속성 값이 비어 있지 않은지, 고유한지, 데이터베이스에 이미 존재하지 않는지, 특정 형식을 따르는지 등을 검증할 수 있습니다.

save, createupdate와 같은 메서드는 모델을 데이터베이스에 영구 저장하기 전에 모델을 검증합니다. 모델이 유효하지 않으면 이러한 메서드는 false를 반환하고 데이터베이스 작업이 수행되지 않습니다. 이러한 모든 메서드에는 뱅 카운터파트(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

유효성 검사에 대해 자세히 알아보려면 Active Record Validations 가이드를 참조하세요.

콜백

액티브 레코드 콜백을 사용하면 모델의 수명 주기에 특정 이벤트에 코드를 연결할 수 있습니다. 이를 통해 새 레코드를 생성하거나 업데이트하거나 삭제할 때와 같은 이벤트에서 모델의 동작을 실행할 수 있습니다.

class User < ApplicationRecord
  after_create :log_new_user

  private
    def log_new_user
      puts "A new user was registered"
    end
end
irb> @user = User.create
A new user was registered

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

마이그레이션

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

다음은 publications라는 새 테이블을 만드는 마이그레이션입니다:

class CreatePublications < ActiveRecord::Migration[7.2]
  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는 어떤 마이그레이션이 데이터베이스에 커밋되었는지 추적하고 동일한 데이터베이스에 있는 schema_migrations라는 인접 테이블에 저장합니다.

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

마이그레이션에 대해 자세히 알아보려면 Active Record Migrations 가이드를 참조하세요.

연관관계

액티브 레코드 연관관계를 사용하면 모델 간 관계를 정의할 수 있습니다. 연관관계는 일대일, 일대다, 다대다 관계를 설명할 수 있습니다. 예를 들어 "Author has many Books"와 같은 관계는 다음과 같이 정의할 수 있습니다:

class Author < ApplicationRecord
  has_many :books
end

Author 클래스에는 이제 책을 추가하고 제거하는 등의 메서드가 있습니다.

연관관계에 대해 자세히 알아보려면 Active Record Associations 가이드를 참조하세요.