Railsチュートリアル 第13章 ユーザーのマイクロポスト - Micropostモデル

# 基本的なモデル

## Micropostモデルが持つ属性

Micropostモデルの基本となる属性は以下の2つです。

* `content`属性
    * マイクロポストの内容
* `user_id`属性
    * 特定のユーザーと、当該マイクロポストを関連付ける

実際には、Railsにより自動生成される属性もあるため、Micropostモデルの全体像は以下のようになります。

![Micropost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/1bbbec47-56ce-d817-00af-3461bbccae35.png)

## `Text`型とは

RDBにおける`Text`型は、（存在する場合）`String`型とは異なる、文字列を内容として格納する型です。Railsチュートリアルでは、`String`型と対比した場合の`Text`型の特徴として、以下の事柄が挙げられています。

* String型に対応するのはテキストフィールドであり、Test型に対応するのはテキストエリアである
    * マイクロポストの投稿フィールドとして用いる場合、1行のテキストフィールドより複数行のテキストエリアのほうが自然である
* 将来における柔軟性に富む
    * 言語に応じて投稿の長さを調整できる、など

以上のような理由から、今回のサンプルアプリケーションにおいて、マイクロポストの投稿・保存は、`Text`型の属性を用いて行うこととします。

## Micropostモデルの生成

モデルを生成するためのコマンドは、`rails generate model`コマンドですね。今回は以下のコマンドを用いてMicropostモデルを生成します。

```
# rails generate model Micropost content:text user:references
Running via Spring preloader in process 1289
      invoke  active_record
      create    db/migrate/20191218224953_create_microposts.rb
      create    app/models/micropost.rb
      invoke    test_unit
      create      test/models/micropost_test.rb
      create      test/fixtures/microposts.yml
```

結果、以下のようなモデルが生成されます。例によって`ApplicationRecord`を継承しています。

```ruby:app/models/micropost.rb
class Micropost < ApplicationRecord
  belongs_to :user
end
```

`user:references`や`belongs_to :user`という、見慣れないコードが存在しますね。大まかには、「RDBのインデックスと外部キー参照が定義された`user_id`カラムを自動追加し、UserとMicropostを紐付けする準備を行う」という意味合いのコードです。これらのコードが意味する事柄については、後の「User/Micropostの関連付け」の項で、より詳しく解説していきます。

## Micropostモデルのマイグレーション

上述`rails generate model`コマンドで生成されたMicropostモデルのマイグレーションは、初期状態では以下のようになっています。

```ruby:db/migrate/[timestamp]_create_microposts.rb
class CreateMicroposts < ActiveRecord::Migration[5.1]
  def change
    create_table :microposts do |t|
      t.text :content
      t.references :user, foreign_key: true

      t.timestamps
    end
  end
end
```

`t.references :user, foreign_key: true`というのも、`user:references`や`belongs_to :user`と同様、UserとMicropostの紐付けに関するコードです。

また、`t.timestamps`というコードが自動で追加されています。「`created_at`属性および`updated_at`属性の定義と、その値の自動保存」を実装するためのコードです。Userモデルのマイグレーションでも、同様のコードが登場していましたね。

### Micropostモデルのマイグレーションに、新たなインデックスを追加する

Micropostモデルにおいては、「`user_id`に関連付けられたすべてのマイクロポストを作成時刻の逆順で取り出す」という主要なユースケースが存在します。当該ユースケースを効率よく実行できるようにするために、必要なインデックスを追加していきましょう。すなわち、「`user_id`属性と`created_at`属性の組に対応するインデックス」ですね。

```diff:db/migrate/[timestamp]_create_microposts.rb
  class CreateMicroposts < ActiveRecord::Migration[5.1]
    def change
      create_table :microposts do |t|
        t.text :content
        t.references :user, foreign_key: true

        t.timestamps
      end
+     add_index :microposts, [:user_id, :created_at]
    end
  end
```

#### 複合キーインデックスとは

RDBにおいて、「複数の属性の組み合わせ」に対して設定されるインデックスのことを指します。「単一の属性では重複が発生する」という場合などに用いられます。なお、日本語では「複合インデックス」や「複数列インデックス」という言い回しのほうがより一般的なようです。

RailsのActive Recordに複合キーインデックスを作成させるには、対応するマイグレーションにおいて、`add_index`の2番目の引数に、複合キーインデックスを構成するすべての属性を指すシンボルを配列で与える必要があります。

例えば、以下のような感じですね。

```ruby:
add_index :microposts, [:user_id, :created_at]
```

## Micropostモデルの生成をRDBに反映する

例によって`rails db:migrate`コマンドです。

```
# rails db:migrate
== [timestamp] CreateMicroposts: migrating =================================
-- create_table(:microposts)
   -> 0.0213s
-- add_index(:microposts, [:user_id, :created_at])
   -> 0.0058s
== [timestamp] CreateMicroposts: migrated (0.0349s) ========================
```

なお、現在RailsサーバーやRailsコンソールが起動されている場合は、先にexitしておく必要があります。そうでないと`rails db:migrate`が失敗します。

# 演習 - 基本的なモデル

## 1.1. Railsコンソールで`Micropost.new`を実行し、インスタンスを変数`micropost`に代入してください。

```
# rails console

>> micropost = Micropost.new
=> #<Micropost id: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil>
```

## 1.2. その後、`user_id`に最初のユーザーのidを、`content`に "Lorem ipsum" をそれぞれ代入してみてください。この時点では、 `micropost`オブジェクトのマジックカラム (`created_at`と`updated_at`) には何が入っているでしょうか?

```
>> micropost[:user_id] = 1
=> 1
>> micropost[:content] = "Lorem ipsum"
=> "Lorem ipsum"

>> pp micropost[:created_at]
nil
>> pp micropost[:updated_at]
nil
```

`created_at`と`updated_at`の内容は、いずれも`nil`になっていますね。

## 2.1. 先ほど作ったオブジェクトを使って、`micropost.user`を実行してみましょう。どのような結果が返ってくるでしょうか?

```
>> micropost.user
  User Load (2.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2019-12-02 23:07:26", updated_at: "2019-12-02 23:07:26", password_digest: "$2a$10$AXWNXZNDu9NkLx3tvgr80umb9xpbx1KwPz9ndp/7Pwr...", remember_digest: nil, admin: true, activation_digest: "$2a$10$Q.bVywQrrgEJC6Mg0IhdXONY5M/0jQYm4/ZEBwhJfxc...", activated: true, activated_at: "2019-12-02 23:07:26", reset_digest: nil, reset_sent_at: nil>
```

`users`テーブルに対し、SQLの`SELECT`文を、抽出対象カラムを`id`・抽出条件を`micropost[:user_id]`として実行しています。

結果、id=1のUserオブジェクトが返ってきます。

## 2.2. また、`micropost.user.name`を実行した場合の結果はどうなるでしょうか?

```
>> micropost.user.name
=> "Example User"

>> User.find(1).name
  User Load (5.6ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> "Example User"
```

id=1であるUserオブジェクトの`name`属性の値が返ってきます。`User.find(1).name`と同じ結果ですね。

## 3.1. 先ほど作った`micropost`オブジェクトをデータベースに保存してみましょう。

```
>> micropost.save
   (0.5ms)  begin transaction
  SQL (19.6ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2019-12-19 05:11:44.579268"], ["updated_at", "2019-12-19 05:11:44.579268"]]
   (9.8ms)  commit transaction
```

特にバリデーションが設定されていないため、何も考えずに`micropost.save`メソッドを実行しても、`micropost`オブジェクトの内容が正しくRDBに保存されます。

## 3.2. この時点でもう一度マジックカラムの内容を調べてみましょう。今度はどのような値が入っているでしょうか?

```
>> pp micropost[:created_at]
Thu, 19 Dec 2019 05:11:44 UTC +00:00

>> pp micropost[:updated_at]
Thu, 19 Dec 2019 05:11:44 UTC +00:00
```

`created_at`および`updated_at`の内容には、先ほどの`micropost.save`のログに表示された時刻と同じ時刻が保存されています。

# Micropostのバリデーション

## Micropostモデルに対する最初のテスト

* `setup`メソッドで与えたMicropostオブジェクトが有効であることを確認する
* `user_id`が存在しないMicropostオブジェクトが有効でないことを確認する

```ruby:test/models/micropost_test.rb
require 'test_helper'

class MicropostTest < ActiveSupport::TestCase
  def setup
    @user = users(:rhakurei)
    #HACK: このコードは慣習的に正しくないため、要修正
    @micropost = Micropost.new(content: "Lorem ipsum", user_id: @user.id)
  end

  test "should be valid" do
    assert @micropost.valid?
  end

  test "user id should be present" do
    @micropost.user_id = nil
    assert_not @micropost.valid?
  end
end
```

## Micropostモデルに対する最初のテストの実行

```
# rails test test/models/micropost_test.rb
Running via Spring preloader in process 1340
Started with run options --seed 11643

  2/2: [===================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.74715s
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
```

現時点においては、当該テストは問題なく成功します。

## Micropostモデルに、テスト駆動で新たな機能を追加していく

長くなりましたので、別記事で解説します。

* [Railsチュートリアル 第13章 ユーザーのマイクロポスト - Micropostモデルに、テスト駆動で新たな機能を追加していく](https://qiita.com/rapidliner00/items/a4b2d842f333e45b310f)

# 演習 - Micropostのバリデーション

## 1.1. Railsコンソールを開き、`user_id`と`content`が空になっている`micropost`オブジェクトを作ってみてください。このオブジェクトに対して`valid?`を実行すると、失敗することを確認してみましょう。

```
>> micropost = Micropost.new
=> #<Micropost id: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil>
>> micropost.valid?
=> false
```

`micropost.valid?`を実行すると、少々の待ち時間の後に`false`という結果が返ってきます。

## 1.2. また、生成されたエラーメッセージにはどんな内容が書かれているでしょうか?

1.1. の続きとなります。

```
>> micropost.errors.full_messages
=> ["User must exist", "Content can't be blank"]
```

* User must exist
* Content can't be blank

以上のエラーメッセージが返ってきていますね。

## 2.1. コンソールを開き、今度は`user_id`が空で`content`が141文字以上の`micropost`オブジェクトを作ってみてください。このオブジェクトに対して`valid?`を実行すると、失敗することを確認してみましょう。

```
>> micropost = Micropost.new(user_id: nil, content: "a" * 141)
=> #<Micropost id: nil, content: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", user_id: nil, created_at: nil, updated_at: nil>
>> micropost.valid?
=> false
```

文字列の乗算により、141文字の文字列を生成し、その内容を`content`の内容としています。

```
"a" * 141
```

## 2.2. また、生成されたエラーメッセージにはどんな内容が書かれているでしょうか?

```
>> micropost.errors.full_messages
=> ["User must exist", "Content is too long (maximum is 140 characters)"]
```

* User must exist
* Content is too long (maximum is 140 characters)

以上のエラーメッセージが返ってきていますね。

# User/Micropostの関連付け

```
# rails generate model Micropost content:text user:references
```

```ruby:（Micropostモデルより）
belongs_to :user
```

```ruby:（Micropostのマイグレーションより）
t.references :user, foreign_key: true
```

Micropostモデルの生成に際して、以上のような見慣れないコードが登場しました。これらはどのような意味を持つのでしょうか。その解説です。

## Micropost belongs to User

![micropost belongs to user.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/16dc7756-34b3-275a-7135-fa53fe033659.png)

MicropostとそのUserは、`belongs_to`（1対1）という関係性があります。

## User has many Microposts

![user has many microposts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/d1972a41-e735-34e6-d198-d949b550736d.png)

UserとそのMicropostには、`has_many`（1対多）という関係性があります。

## モデル定義に記述する、`belongs_to`と`has_many`

まず、Micropostモデルに`belongs_to :user`というコードが必要になります。ただ、このコードは、Micropostモデルの生成時点で自動で生成されています。

```ruby:app/models/micropost.rb
class Micropost < ApplicationRecord
  belongs_to :user
  # ...略
end
```

さらに、Userモデルに`has_many :microposts`というコードが必要になります。こちらは手動で追加する必要があります。

```diff:app/models/user.rb
  class User < ApplicationRecord
+   has_many :microposts
    ...略
  end
```

## User/Micropost関連メソッド

上述の`belongs_to`や`has_many`というモデル同士の関係性をモデルに記述することにより、以下のようなメソッドを利用することが可能になります。

|メソッド名|用途|
|-----|-----|
|`micropost.user`|Micropostに紐付いたUserオブジェクトを返す|
|`user.microposts`|Userのマイクロポストの集合を返す|
|`user.microposts.create(arg)`|`user`に紐付いたマイクロポストを生成する。失敗時には`nil`を返す|
|`user.microposts.create!(arg)`|`user`に紐付いたマイクロポストを生成する。失敗時には例外を発生させる|
|`user.microposts.build(arg)`|`user`に紐付いた新しいMicropostオブジェクトを返す|
|`user.microposts.find_by(id: 1)`|`user`に紐付いていて、`id`が`1`であるマイクロポストを検索する|

## Micropostモデルに対するテストの`setup`メソッドを、慣習的に正しいマイクロポストの生成方法に書き換えていく

関連するモデルに`belongs_to`と`has_many`を実装すれば、慣習的に正しいマイクロポストの生成を実装できるようになります。`test/models/micropost_test.rb`の`setup`メソッドを、慣習的に正しいマイクロポストの生成方法に書き換えていきましょう。

```diff:test/models/micropost_test.rb
  require 'test_helper'

  class MicropostTest < ActiveSupport::TestCase
    def setup
      @user = users(:rhakurei)
-     #HACK: このコードは慣習的に正しくないため、要修正
-     @micropost = Micropost.new(content: "Lorem ipsum", user_id: @user.id)
+     @micropost = @user.microposts.build(content: "Lorem ipsum")
    end

    test "should be valid" do
      assert @micropost.valid?
    end

    test "user id should be present" do
      @micropost.user_id = nil
      assert_not @micropost.valid?
    end

    test "content should be present" do
      @micropost.content = "  "
      assert_not @micropost.valid?
    end

    test "content should be at most 140 characters" do
      @micropost.content = "a" * 141
      assert_not @micropost.valid?
    end
  end
```

### Micropostモデルに対するテストの`setup`メソッドを、慣習的に正しいマイクロポストの生成方法をテストで実装すると、テストが成功しなくなる

この時点で`test/models/micropost_test.rb`に対するテストを実行すると、テストが成功しなくなります。

```
# rails test test/models/micropost_test.rb
Running via Spring preloader in process 1476
Started with run options --seed 20502

 FAIL["test_user_id_should_be_present", MicropostTest, 0.7893391999969026]
 test_user_id_should_be_present#MicropostTest (0.79s)
        Expected true to be nil or false
        test/models/micropost_test.rb:15:in `block in <class:MicropostTest>'

  4/4: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.81867s
4 tests, 4 assertions, 1 failures, 0 errors, 0 skips
```

私の環境では、`test/models/micropost_test.rb`の14行目〜15行目の内容は以下のようになっています。

```ruby:test/models/micropost_test.rb（14〜15行目）
@micropost.user_id = nil
assert_not @micropost.valid?
```

「`@micropost.user_id`が`nil`であるのに、`@micropost.valid?`が`true`を返してしまっている」という失敗ですね。

## Micropostモデルに、ユーザーの存在性を検証するバリデーションを追加する

先ほどの問題を解消するためには、Micropostモデルに、ユーザーの存在性を検証するバリデーションを追加する必要があります。`app/models/micropost.rb`のコードの変更点は以下のとおりです。

```diff:app/models/micropost.rb
  class Micropost < ApplicationRecord
    belongs_to :user
+   validates :user_id, presence: true
    validates :content, presence: true, length: { maximum: 140 }
  end
```

上記変更を反映した後に、再びテストを実行してみます。

```
# rails test test/models/micropost_test.rb
Running via Spring preloader in process 1489
Started with run options --seed 47152

  4/4: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.87582s
4 tests, 4 assertions, 0 failures, 0 errors, 0 skips
```

今度はテストが成功するようになります。

# 演習 - User/Micropostの関連付け

## 1. データベースにいる最初のユーザーを変数`user`に代入してください。その`user`オブジェクトを使って`micropost = user.microposts.create(content: "Lorem ipsum")`を実行すると、どのような結果が得られるでしょうか?

```
>> user = User.first

>> micropost = user.microposts.create(content: "Lorem ipsum")
   (0.1ms)  begin transaction
  SQL (15.5ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2019-12-20 13:10:45.903917"], ["updated_at", "2019-12-20 13:10:45.903917"]]
   (10.2ms)  commit transaction
=> #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2019-12-20 13:10:45", updated_at: "2019-12-20 13:10:45">
```

実際に生成されたマイクロポストが返ってきています。

## 2.1. 先ほどの演習課題で、データベース上に新しいマイクロポストが追加されたはずです。user.microposts.find(micropost.id)を実行して、本当に追加されたのかを確かめてみましょう。

```
>> user.microposts.find(micropost.id)
  Micropost Load (6.3ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? AND "microposts"."id" = ? LIMIT ?  [["user_id", 1], ["id", 2], ["LIMIT", 1]]
=> #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2019-12-20 13:10:45", updated_at: "2019-12-20 13:10:45">
```

確かに 1. で追加されたマイクロポストを返してきています。

### 2.2. また、先ほど実行した`micropost.id`の部分を`micropost`に変更すると、結果はどうなるでしょうか?

```
>> user.microposts.find(micropost)
Traceback (most recent call last):
        1: from (irb):5
ArgumentError (You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`.)
```

`ArgumentError`を投げてきていますね。

「`.find`に`ActiveRecord::Base`を継承したオブジェクトそのものを渡すと`ArgumentError`を投げる」というのは、Rails 5.1 以降の仕様となります。 - [rails/CHANGELOG.md at v5.1.0 · rails/rails · GitHub](https://github.com/rails/rails/blob/v5.1.0/activerecord/CHANGELOG.md)

> ```md:
> Raise ArgumentError when passing an ActiveRecord::Base instance to .find, > .exists? and .update.
> 
> Rafael Mendonça França
> ```

## 3.1. `user == micropost.user`を実行した結果はどうなるでしょうか?

```
>> user == micropost.user
=> true
```

## 3.2. また、`user.microposts.first == micropost`を実行した結果はどうなるでしょうか? それぞれ確認してみてください。

```
>> user.microposts.first == micropost
  Micropost Load (27.9ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."id" ASC LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
=> false
```

当該ユーザーにより、今回の演習 1. 以前に一度マイクロポストを追加したことがありました。そのため、今回追加したマイクロポストと`user.microposts.first`は一致せず、`user.microposts.first == micropostは`false`を返します。

```
>> user.microposts.first
  Micropost Load (7.8ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."id" ASC LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2019-12-19 05:11:44", updated_at: "2019-12-19 05:11:44">
```

# マイクロポストを改良する

## マイクロポストが投稿日時の降順（＝新しい順）に表示されるようにする

「マイクロポストが投稿日時の降順（＝新しい順）に表示されるようにする」という実装を、Micropostモデルに追加します。実装およびテストについては、別記事で解説します。

* [Railsチュートリアル 第13章 ユーザーのマイクロポスト - 「マイクロポストが投稿日時の降順（＝新しい順）に表示されるようにする」という実装を、Micropostモデルに追加する](https://qiita.com/rapidliner00/items/ad4842a6ced2d4df66c5)

## ユーザーが削除されると、当該ユーザーのマイクロポストも同時に破棄されるようにする

「ユーザーが削除されると、当該ユーザーのマイクロポストも同時に破棄されるようにする」という実装を、Userモデルに追加します。実装およびテストについては、別記事で解説します。

[Railsチュートリアル 第13章 ユーザーのマイクロポスト - 「ユーザーが削除されると、当該ユーザーのマイクロポストも同時に破棄されるようにする」という実装を、Userモデルに追加する」](https://qiita.com/rapidliner00/items/fe70e6ade03285e45342)

# 演習 - マイクロポストを改良する

## 1. `Micropost.first.created_at`の実行結果と、`Micropost.last.created_at`の実行結果を比べてみましょう。

```
>> Micropost.first.created_at
  Micropost Load (14.9ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC LIMIT ?  [["LIMIT", 1]]
=> Fri, 20 Dec 2019 13:10:45 UTC +00:00

>> Micropost.last.created_at
  Micropost Load (0.5ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LIMIT ?  [["LIMIT", 1]]
=> Thu, 19 Dec 2019 05:11:44 UTC +00:00
```

確かに`Micropost.first.created_at`の結果の日時よりも、`Micropost.last.created_at`の日時のほうが過去の日時となっています。

## 2. `Micropost.first`を実行したときに発行されるSQL文はどうなっているでしょうか? 同様にして、`Micropost.last`の場合はどうなっているでしょうか?

> ヒント: それぞれをコンソール上で実行したときに表示される文字列が、SQL文になります。

```
>> Micropost.first
  Micropost Load (0.3ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" DESC LIMIT ?  [["LIMIT", 1]]

>> Micropost.last 
  Micropost Load (0.3ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."created_at" ASC LIMIT ?  [["LIMIT", 1]]
```

`first`のほうのSQL文には`DESC`という句が含まれており、一方`last`のほうのSQL文には`ASC`という句が含まれています。

## 3.1. データベース上の最初のユーザーを変数userに代入してください。その`user`オブジェクトが最初に投稿したマイクロポストの`id`はいくつでしょうか?

```
>> user = User.first
  User Load (1.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, ...>

>> user.microposts.last.id
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" ASC LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
=> 1
```

現状の実装において、「ユーザーが最初に投稿したマイクロポスト」というのは、`user.microposts.last`というメソッドで取得することができます。その`id`のみを取得するのであれば、`user.microposts.last.id`というメソッドですね。

`user.microposts.last.id`の戻り値は`1`ですね。

## 3.2. 次に、`destroy`メソッドを使ってその`user`オブジェクトを削除してみてください。削除すると、その`user`に紐付いていたマイクロポストも削除されていることを`Micropost.find`で確認してみましょう。

```
>> user.destroy
   (0.2ms)  SAVEPOINT active_record_1
  Micropost Load (0.4ms)  SELECT "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC  [["user_id", 1]]
  SQL (18.6ms)  DELETE FROM "microposts" WHERE "microposts"."id" = ?  [["id", 2]]
  SQL (0.2ms)  DELETE FROM "microposts" WHERE "microposts"."id" = ?  [["id", 1]]
  SQL (5.6ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1

>> Micropost.find(1)
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ?  [["id", 1], ["LIMIT", 1]]
Traceback (most recent call last):
        1: from (irb):11
ActiveRecord::RecordNotFound (Couldn't find Micropost with 'id'=1)
```

ポイントは以下です。

* `user`オブジェクトの`destroy`メソッドを実行した時点で、`microposts`テーブルのレコードに対してもSQL文`DELETE`がいくつか発行されている
    * 削除対象のレコードを確定するために、当該ユーザーの`id`を`WHERE`句に持つSQL文`SELECT`が発行されている
* 削除されたマイクロポストのIDを引数に取って`Micropost.find`を実行すると、`ActiveRecord::RecordNotFound`というエラーが投げられてくる

#### 余談 - Userモデルの`has_many`メソッドに`dependent: :destroy`オプションがない場合

```
>> user.destroy
   (0.6ms)  SAVEPOINT active_record_1
  SQL (25.4ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 1]]
   (0.2ms)  ROLLBACK TO SAVEPOINT active_record_1
Traceback (most recent call last):
        1: from (irb):20
ActiveRecord::InvalidForeignKey (SQLite3::ConstraintException: FOREIGN KEY constraint failed: DELETE FROM "users" WHERE "users"."id" = ?)
```

`user.destroy`が`ActiveRecord::InvalidForeignKey`というエラーで失敗します。