rails: 一对多关联(belongs_to/has_many)

在 Rails 中,对于 AuthorBook 之间的 1 对多关系,Author 拥有多个 Book,而 Book 属于一个 Author。你可以按照以下步骤来定义这种关系。

01 基本共识

在 Rails 的一对多关联中,belongs_to 的一方需要在数据库中存储外键,因此需要在 Bookbelongs_to 的一方)添加 :references

02 更简单的理解方式

  • Author 拥有多个 BookAuthorhas_many 这一方)。
  • Book 属于一个 AuthorBookbelongs_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)
rails orm belongs_to has_many rubyonrails