rails: 一对多关联(belongs_to/has_many)
在 Rails 中,对于 Author
和 Book
之间的 1 对多关系,Author
拥有多个 Book
,而 Book
属于一个 Author
。你可以按照以下步骤来定义这种关系。
01 基本共识
在 Rails 的一对多关联中,belongs_to
的一方需要在数据库中存储外键,因此需要在 Book
(belongs_to
的一方)添加 :references
02 更简单的理解方式
Author
拥有多个Book
(Author
是has_many
这一方)。Book
属于一个Author
(Book
是belongs_to
这一方)。
因此,我们需要在 Book
模型中存储 author_id
来表示每本书的作者是谁,所以 :references
应该加在 Book
模型中。
03 生成 model 命令
命令模板,谁上面写 author_id,谁上面就写
author:references
rails g model Author name:string
rails g model Book title:string author:references
author:references
表示 Book
表中将会自动添加一个 author_id
字段,并创建与 Author
模型的关联
04 在模型中定义关联关系 - auhor(1方)
app/models/author.rb
class Author < ApplicationRecord
has_many :books, dependent: :destroy
# validations
validates :name, presence: true
end
has_many :books
表示一个 Author
拥有多本 Book
05 在模型中定义关联关系 - book(N方)
app/models/book.rb
class Book < ApplicationRecord
belongs_to :author
end
belongs_to :author
表示每本 Book
都属于一个 Author
。
06 数据库迁移
./bin/rails db:migrate
通过这种方式,Book
模型会自动带有 author_id
字段,代表每本书对应的作者。
07 其它信息
以下是使用
author:references
和手动定义author_id
的等效写法。rails g model Book title:string author_id:integer:index 是这样吗?
是的,你的命令几乎正确,但略有调整建议。要手动生成一个带有 `author_id` 字段,并且自动添加索引的 `Book` 模型,命令应该是:
```bash
rails g model Book title:string author_id:integer:index
```
这个命令会生成一个 `author_id` 字段,并自动为该字段创建索引。
### 生成的迁移文件示例:
```ruby
class CreateBooks < ActiveRecord::Migration[6.0]
def change
create_table :books do |t|
t.string :title
t.integer :author_id
t.index :author_id # 这行自动添加索引
t.timestamps
end
end
end
```
### 手动添加外键约束:
此命令只会生成 `author_id` 和索引,但不会自动添加外键约束。如果你想要外键约束,需要在迁移文件中手动添加:
```ruby
class CreateBooks < ActiveRecord::Migration[6.0]
def change
create_table :books do |t|
t.string :title
t.integer :author_id
t.index :author_id
t.timestamps
end
# 手动添加外键约束
add_foreign_key :books, :authors
end
end
```
### 最后,别忘了在模型中定义关联:
#### `app/models/book.rb`:
```ruby
class Book < ApplicationRecord
belongs_to :author # 手动添加关联
end
```
这样就达到了手动控制 `author_id` 的效果,同时保留索引和外键约束。
08 创建实例
创建 book
要在 Rails 中创建
Book
实例并与Author
关联,你需要先创建一个Author
,然后使用这个作者来创建对应的Book
。以下是几个常用的创建Book
的方式。
# 方式1. 先创建 Author,再创建 Book ----------------------------
# 创建一个作者
author = Author.create(name: "J.K. Rowling")
# 通过 author_id 来创建一本书
book = Book.create(title: "Harry Potter and the Sorcerer's Stone", author_id: author.id)
# 方式2. 使用关联来创建 Book ----------------------------
# 通过关联来创建书
book = author.books.create(title: "Harry Potter and the Chamber of Secrets")
# 方式3. 先创建 Book,再关联 Author ----------------------------
# 创建一本书,但暂时不指定作者
book = Book.create(title: "Harry Potter and the Prisoner of Azkaban")
# 后来再关联作者
book.author = author
book.save
# 或者使用 update
book.update(author: author)