Ruby on Rails チュートリアル 第13章 メモ&演習 モデルの関連付け マイクロポストの表示 画像投稿機能の実装

#近況報告

エンジニア転職成功しました。YouTubeもはじめました。

https://www.youtube.com/channel/UCcXQG8lu_EdyP2Cbhtz1bcA


[前回の続き](https://qiita.com/yuuki_netb/items/04f3b87aac87ee359ed5)

著者略歴
著者：[YUUKI](https://twitter.com/bitcoinjpnnet)
ポートフォリオサイト：[Pooks](https://pooks.herokuapp.com/)
現在：RailsTutorial2周目

#第13章　ユーザーのマイクロポスト　難易度 ★★★★★　8時間
<b>挫折しないRailsチュートリアルの進め方を先にお読みください↓↓</b>

[Railsチュートリアルで挫折しない３つのポイント](https://webnewage.com/rails-tutorial-point)

これまでに

-　ユーザー
-　セッション
-　アカウント有効化
-　パスワードリセット

という4つのリソースについて見てきた。

このうち、**ユーザーというリソースだけが、Active RecordによってDB上のテーブルと紐づいている。**


サンプルアプリのコア部分に関しての準備が整ったので、今回は
**ユーザーが短いメッセージを投稿できるようにするマイクロポスト**
を追加していく。


第2章ではScaffoldを使って簡易的なマイクロポスト投稿フォームに触れたが、
この章では

- Micropostデータモデルを作成
- Userモデルと`has_many`および`belongs_to`メソッドを使って関連付けを行う
- 結果を処理し表示するために必要なフォームとその部品
- 画像のアップロード機能

を作成する。



##13.1 Micropostモデル

まずはMicropostリソースの本質的な部分である`Micropost`モデルを作成するところから始める。

2章で作成したモデルと同様に、この新しいMicropostモデルも
**データ検証**と**Userモデルの関連付け**を含んでいる。


以前のモデルとは違い、今回のマイクロポストモデルは完全にテストされ、デフォルトの順序を待ち、また親であるユーザーが破棄された場合には自動的に破棄されるようにする。

Gitをバージョン管理に使っている場合は、いつものようにトピックブランチを作成しておく。

```ruby
$ git checkout -b user-microposts
```


13.1.1 基本的なモデル

Micropostsモデルは、

- マイクロポストの内容を保存するcontent属性
- 特定のユーザーとマイクロポストを関連付けるuser_id属性

の２つの属性だけを持つ。

実行した結果のMicropostsモデルの構造

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/f38e2da2-c2b5-4553-74cf-6c750a48fd0f.png)

出典：[図 13.1: Micropostデータモデル](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)


マイクロポストの投稿にString型ではなく、`Text型`を使っている点に注目。

違いを簡単に説明すると

- String型

255文字以内の文字列を格納するデータ型

- Text型

制限なしの可変長文字列を格納できるデータ型

Text型の方が汎用性に富んでおり、Webサービスを国際化する時にも言語に応じて投稿の長さを調節することもできる。

さらに、Text型を使っていても本番環境でパフォーマンスの差は出ない。


これらのメリットから、今回はText型を採用する。


6章でUserモデルを生成した時と同様、`g model`コマンドでMicropostモデルを生成する。


```ruby
$ rails g model Microposts content:text user:references
```

このコマンドで6章の時と同様、`ApplicationRecord`を継承したモデルが作られる。

ただし、今回は`user:references`という引数を含めているので、
**ユーザーと1対1の関係であることを表す`belongs_to`のコードも追加されている。**

この部分に関しては後に詳解する。


```rb:microposts.rb
class Micropost < ApplicationRecord
  belongs_to :user
end
```

6章でDBにusersテーブルを作るマイグレーションを生成した時と同様に、
このgコマンドは`microposts`テーブルを作成するためのマイグレーションファイルを生成する。


Userモデルとの最大の違いは`references型`を利用している点。

これを利用すると、自動的にインデックスと外部キー参照付きの`user_idカラム`が追加され、
**UserとMicropostを関連付けする下準備をしてくれる。**

Userモデルの時と同じで、Micropostモデルのマイグレーションファイルでも`t.timestamps`という行(マジックカラム)が自動的に生成されている。

これにより、`created_at`(作成日時)と`update_at`(更新日時)というカラムが追加される。

なお、`created_at`カラムは今後の実装を進めていく上で必要なカラムとなるので追加しておく。

```rb:[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 ]                            # user_idとcreate_atカラムにインデックス(要素番号)を付与
  end
end
```

`add_index`で`user_id`と`created_at`カラムを指定することで、インデックスを付与することができる。

こうすると、
**User_idに関連づけられた全てのマイクロポストを作成時刻の逆順で取り出しやすくなる。**

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

また、両方を１つの配列に含めている点にも注目。

こうすることで、Active Recordは、
**両方のキーを同時に扱う複合キーインデックス(Multiple key Index)を作成する。**

あとはマイグレーションを使ってDBを更新する。

```ruby
$ rails db:migrate
```

####演習

1:Railsコンソールで`Micropost.new`を実行し、インスタンスを変数`micropost`に代入。
その後、user_idに最初のユーザーidを、contentに"Lorem ipsum"をそれぞれ代入。

この時点で、micropostオブジェクトのマジックカラムには何が入っているか？

```ruby
>> micropost = Micropost.new
=> #<Micropost id: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil>
>> micropost.user_id = User.first.id
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 1
>> micropost.content = "Lorem ipsum"
=> "Lorem ipsum"
>> micropost.created_at
=> nil
>> micropost.updated_at
=> nil
```

2:先ほど作ったオブジェクトを使って`micropost.user`実行結果と、`micropost.user.name`を実行した場合の結果をみる

```ruby
>> micropost.user
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "YUUKI", email: "〇〇@gmail.com", created_at: "2019-01-27 11:45:56", updated_at: "2019-01-28 10:06:18", password_digest: "$2a$10$RtF8nSd22GLENhTmlBTkPeaqyPEs9E8v7f3UeR6UecG...", remember_digest: nil, admin: false, ¥: nil, activation_digest: "$2a$10$f3kgl8ZWwRuixqBNDohcb.qkPwxw1Pq2gocBSz116gM...", activated: true, activated_at: "2019-01-27 11:46:05", reset_digest: "$2a$10$cs997A4KK0w9hg0OOW3WA.6cv82z0gw06pZOzIX3x/p...", reset_sent_at: "2019-01-28 10:05:13">
>> micropost.user.name
=> "YUUKI"
```

micropostにidを付与することで、userとnameがきちんと紐づいている。

3:先ほど作ったmicropostオブジェクトをDBに保存して、もう一度マジックカラムの内容を調べてみる。

```ruby
>> micropost.save
   (0.1ms)  begin transaction
  SQL (1.7ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2019-01-29 07:36:23.181786"], ["updated_at", "2019-01-29 07:36:23.181786"]]
   (7.9ms)  commit transaction
=> true
>> micropost.created_at
=> Tue, 29 Jan 2019 07:36:23 UTC +00:00
>> micropost.updated_at
=> Tue, 29 Jan 2019 07:36:23 UTC +00:00
```


###13.1.2 Micropostのバリデーション

基本的なモデルを作成したので、次に要求される制限を実現するためのバリデーションを追加する。

Micropostモデルを作成した時に、マイクロポストは投稿したユーザーのid(user_id)を持たせるようにした。

これを使って、慣習的に正しくActive Recordの関連付けを実装していく。


まずは、Micropostモデル単体をテスト駆動開発で動くようにする。


Micropostの初期テストはUserモデルの初期テストと似ている。

そのステップは

- setupのステップで、fixtureのサンプルユーザーと紐付けた新しいマイクロポストを作成
- 作成したマイクロポストが有効かどうかチェック
- あらゆるマイクロポストはユーザーのidを持っているべきなので、`user_id`の存在性のバリデーションに対するテスト


このステップで追加する。


```rb:micropost_test.rb
require 'test_helper'

class MicropostTest < ActiveSupport::TestCase
  def setup
    @user = users(:michael)
    @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
```

setupメソッドの中の、マイクロポストを作成するコードは動くが、慣習的には正しくない。

元々あるUserモデルのテストと同じで、
１つ目のテストでは、正常な状態かどうかをテストしている。

2つ目のテストでは、user_idが存在しているかどうか(nilではないかどうか)をテストしている。

このテストをパスさせる為に、存在性のバリデーションを追加する。

```rb:micropost.rb
class Micropost < ActiveRecord::Base
  belongs_to :user
  validates :user_id, presence: true
```

Rails5では上記のバリデーションを追加していなくてもテストが成功する。
しかし、これは上記の`micropost_new`のコードを書いた場合のみ発生する。

**この部分を、慣習的に正しいコードを書くと、user_idに対する存在性のバリデーションが期待通りに動く。**


以上の背景を踏まえると、今の所テストは成功する。

```ruby
$ rails test:models
```

次に、**マイクロポストのcontent属性に対するバリデーションを追加する**

- content属性が存在する
- 140文字より長くならない

このような制限を加える。

6章でUserモデルにバリデーションを追加した時と同様に、
テスト駆動開発でMicropostモデルのバリデーションを追加していく。

基本的には、Userモデルのときと同じようなバリデーションを追加していく。

```rb:micropost_test.rb
  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
```

マイクロポストの長さをテストする為に、実際にコンソールで文字列の乗算を使う。

```ruby
>> "a" * 10                                                                                                                                                     
=> "aaaaaaaaaa"
>> "a" * 141
=> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
```


これに対応するアプリケーション側の実装は、Userのname用バリデーションと全く同じ。

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

これで、テストはパスする。

```ruby
15 tests, 19 assertions, 0 failures, 0 errors, 0 skips
```

####演習

1:Railsコンソールでuser_idとcontentが空になっているmicropostオブジェクトを作ってみる。
このオブジェクトに対してvalid?を実行すると、失敗することを確認。
生成されたエラーメッセージにはどんな内容が書かれているか？

```ruby
>> micropost = Micropost.new(user_id: "",content: "")                                                                                                           
=> #<Micropost id: nil, content: "", user_id: nil, created_at: nil, updated_at: nil>
>> micropost.valid?
=> false
>> micropost.errors.full_messages
=> ["User must exist", "User can't be blank", "Content can't be blank"]
>> 
```

2:コンソールを開き、今度はuser_idが空でcontentが141文字以上のmicropostオブジェクトを作ってみる。
このオブジェクトに対してvalid?を実行すると、失敗することを確認。
エラーメッセージについても確認する。

```ruby
>> micropost = Micropost.new(user_id: "",content: "a" * 141)
=> #<Micropost id: nil, content: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", user_id: nil, created_at: nil, updated_at: nil>
>> micropost.valid?
=> false
>> micropost.errors.full_messages
=> ["User must exist", "User can't be blank", "Content is too long (maximum is 140 characters)"]
```

###13.1.3 User/Micorpostの関連付け

Webアプリケーション用のデータモデルを構築するにあたって、個々のモデル間での関連付けを十分に考えておく必要がある。

今回の場合は、

①それぞれのマイクロポストは1人のユーザーと関連付けられ、
②それぞれのユーザーは複数のマイクロポストと関連付けられる。

つまり

ユーザー(１)(user)　対　マイクロポスト（１）(micropost.user)
ユーザー(１)(user)　対　マイクロポスト（多）(user.microposts)

の関連付けとなっている。

この関連付けを実装するための一環として、Micropostモデルに対するテストを作成し、さらにUserモデルにいくつかのテストを追加する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/115cc48c-4300-8549-293e-8a5eb1e13f4f.png)

出典：[図 13.2: MicropostとそのUserは belongs_to (1対1) の関係性がある](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/caeb6582-aba6-fc77-4239-a24f0ad86bba.png)

出典：[図 13.3: UserとそのMicropostは has_many (1対多) の関係性がある
](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)


`belongs_to/has_many`関連付けを使うことで、下記の表のようなメソッドを使えるようになる。


![スクリーンショット 2019-01-30 13.00.57.png](https://qiita-image-store.s3.amazonaws.com/0/244639/1cc4ddb5-3435-4efe-f4d4-8cf8cfc8e008.png)

出典：[表 13.1: user/micropost関連メソッドのまとめ](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

また、下記のメソッドではなく

```ruby
Micropost.create
Micropost.create!
Micropost.new
```

このメソッドになっている点に注意。

```ruby
user.microposts.create
user.microposts.create!
user.microposts.bulid
```

これらのメソッドを使うことで、紐付いているユーザーを通してマイクロポストを作成することができる。

新規のマイクロポストがこの方法で作成される場合、`user_id`は自動的に正しい値に設定される。
この方法を使うと、例えば次のような

```ruby
@user = users(:michael)
# このコードは慣習的に正しくない
@micropost = Micropost.new(content: "Lorem ipsum", user_id: @user.id)
```

このような書き方を

```ruby
@user = users(:michael)
@microposts = @user.microposts.bulid(content: "Lorem ipsum")
```

という書き方に変更できる。

newメソッドと同様に、bulidmメソッドはオブジェクトを返すがDBに反映されない。
一度正しい関連付けを定義してしまえば、@microposts変数のuser_idには、関連するユーザーのidが自動的に設定される。

`@user.microposts.bulid`のようなコードを使うためには、UserモデルとMicropostモデルをそれぞれ更新して、関連付ける必要がある。
Micropostモデルの方では、`belongs_to:user`というコードが必要になるが、これはマイグレーションによって自動的に生成されているはず。

一方、Userモデルの方では、`has_many:microposts`と追加する必要がある。

ここは自動的に生成されないので、手動で追加する。

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

```rb:user.rb
class User < ApplicationRecord
  # 関連付け
  has_many :microposts
```

正しく関連付けできたら、setupメソッドを修正して、慣習的に正しくマイクロポストを作成してみる。

```rb:micropost_test.rb
require 'test_helper'

class MicropostsTest < ActiveSupport::TestCase

  def seup
    @user = users(:michael)
    @micropost = @user.microposts.build(content: "Lorem ipsum")
  end

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

end
```

これでテストはパスする。

```ruby
$ rails t
```

####演習

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

```ruby
>> user = User.first
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "YUUKI", email: "〇〇@gmail.com", created_at: "2019-01-27 11:45:56", updated_at: "2019-01-28 10:06:18", password_digest: "$2a$10$RtF8nSd22GLENhTmlBTkPeaqyPEs9E8v7f3UeR6UecG...", remember_digest: nil, admin: false, ¥: nil, activation_digest: "$2a$10$f3kgl8ZWwRuixqBNDohcb.qkPwxw1Pq2gocBSz116gM...", activated: true, activated_at: "2019-01-27 11:46:05", reset_digest: "$2a$10$cs997A4KK0w9hg0OOW3WA.6cv82z0gw06pZOzIX3x/p...", reset_sent_at: "2019-01-28 10:05:13">
>> micropost = user.microposts.create(content: "Lorem ipsum")
   (0.1ms)  begin transaction
  SQL (2.4ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "Lorem ipsum"], ["user_id", 1], ["created_at", "2019-01-30 05:30:17.137853"], ["updated_at", "2019-01-30 05:30:17.137853"]]
   (8.3ms)  commit transaction
=> #<Micropost id: 2, content: "Lorem ipsum", user_id: 1, created_at: "2019-01-30 05:30:17", updated_at: "2019-01-30 05:30:17">
```

2:先ほどの演習問題で、DB上に新しいマイクロポストが追加された。
`user.microposts.find(micropost.id)`を実行して、本当に追加されたのかを確かめる。

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

```ruby
>> user.microposts.find(micropost.id)
  Micropost Load (0.2ms)  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-01-30 05:30:17", updated_at: "2019-01-30 05:30:17">

>> user.microposts.find(micropost)
ArgumentError: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`.
        from (irb):4
```

3: `user == micropost.user`を実行した結果はどうなるか？
また、`user.microposts.first == micropost`を実行した結果はどうなるか？

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


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

これからUserとMicropostの関連付けを改良していく

具体的には、

①ユーザーのマイクロポストを特定の順序で取得できるようにする
②マイクロポストをユーザーに依存させて、ユーザーが削除されたらマイクロポストも自動的に削除されるにする

####デフォルトスコープとは？

`user.microposts`メソッドはデフォルトでは読み出しの順序に対して何も保証しないが、
ブログやTwitterの慣習に従って、作成時間の逆順、
**つまり最も新しいマイクロポストを最初に表示するようにする（降順）**

これを実装する為に、`default scope`というテクニックを使う。

この機能のテストは、**アプリケーション側の実装が本当は間違っているのにテストが成功してしまう場合がある。**

よって、正しいテスト駆動開発で進めていく。
具体的には、まずDB上の最初のマイクロポストが(Micropost.first)が、fixture内のマイクロポスト（most_recent）と同じであるか検証するテストを書く。

```rb:micropost_test.rb
  test "order should be most recent first" do
    assert_equal microposts(:most_recent), Micropost.first
  end
```

`:most_recent`エア、マイクロポスト用のfixtureファイルからサンプルデータを読み出しているので、次のfixtureファイルも必要になる。

```yml:microposts.yml
orange:
  content: "I just ate an orange!"
  created_at: <%= 10.minutes.ago %>

tau_manifesto:
  content: "Check out the @tauday site by @mhartl: http://tauday.com"
  created_at: <%= 3.years.ago %>

cat_video:
  content: "Sad cats are sad: http://youtu.be/PKffm2ul4dk"
  created_at: <%= 2.hours.ago %>

most_recent:
  content: "Writing a short test"
  created_at: <%= Time.zone.now %>
```

ここで、埋め込みRubyを使って`created_at`カラムに明示的に値をセットしている点に注目。

このマジックカラムはRailsによって自動的に更新されるため、基本的には手動で更新することはできないが、
**fixtureファイルの中ではそれが可能**

また、原理的には必要はないかもしれませんが、ほとんどのシステムでは上から順に作成されるので、
**fixtureファイルでも意図的に順序をいじっている。**

昇順でデータが生成されるので、一番最後に生成された`most_recent:`が
最も新しい投稿になるように修正する。

ただ、この振る舞いはシステムに依存していて崩れやすいので、この振る舞いに依存したテストは書くべきではない。

```ruby
$ rails test test/models/micropost_rest.rb
```

このテストでは現在は失敗する。

テストを成功させる方法として、Railsの`default_scope`メソッドを使ってこのテストを成功させる。
このメソッドは、**DBから要素を取得したときのデフォルトの順序を指定するメソッド**。

特定の順序にしたい場合は、`default_scope`の引数に`order`を与える

例えば、created_atカラムの順にしたい場合

```ruby
order(:created_at)
```

このように書く。
ただし、**デフォルトの順序が昇順**となっているので、
このままでは数の小さい値から大きい値にソートされてしまう。

順序を逆にしたい場合は、次のように生のSQLを引数に与える必要がある。

```ruby
order('created_at DESC')
```

DESCとは、SQLの降順(descending)を指す。
したがって、これで新しい投稿から古い投稿順(降順)に並ぶ。

このように書くことも可能

```ruby
order(created_at: :desc)
```

このコードを使ってMicropostモデルを更新する。

```rb:micropost.rb
class Micropost < ApplicationRecord
  belongs_to :user
  default_scope -> { order(created_at: :desc) }                                 # 並び順を降順に変更
  validates :user_id, presence: true
  validates :content, presence: true, length: { maximum: 140 }
end
```

これでテストはパスする。

```ruby
5 tests, 5 assertions, 0 failures, 0 errors, 0 skips
```

ちなみに、`->`はラムダ式と呼ばれる文法を使っているので、呼び出し時に降順にソートされる。
(単語集参照)

#### Dependent: destroy

マイクロポストに第二の要素を追加してみる。
サイト管理者はユーザーを破棄する権限があるが、ユーザーが破棄された場合、
ユーザーのマイクロポストも破棄されるようにする必要がある。

この振る舞いを実現させるため、
`has_many`にオブションとして`dependent: :destroy`を渡す。

```rb:user.rb
class User < ApplicationRecord
  # 関連付け
  has_many :microposts, dependent: :destroy
```

これでユーザーが削除された時に、そのユーザーに紐付いたマイクロポストも一緒に削除されるようになる。

管理者がシステムからユーザーを削除した時、マイクロポストだけがDBに取り残される問題を防ぐ。


次に上記の振る舞いが正しく動くかどうか、テストを使って検証する。

このテストでは

①idを紐づけるためのユーザーを作成する
②そのユーザーに紐付いたマイクロポストを作成
③ユーザーを削除
④マイクロポストの数が１つ減っているかどうか

この順でテストする。


```rb:user_test.rb
  test "associated microposts should be destroyed" do
    @user.save
    @user.microposts.create!(content: "Lorem ipsum")
    assert_difference 'Micropost.count', -1 do
      @user.destroy
    end
  end
```

Userモデルが正しく動いていればテストはパスする。

```ruby
12 tests, 16 assertions, 0 failures, 0 errors, 0 skips
```


####演習

1:`Micropost.first.created_at`の実行結果と、`Micropost.last.created_at`の実行結果を比べみる。

```ruby
>> Micropost.first.created_at
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> Tue, 29 Jan 2019 07:36:23 UTC +00:00
>> Micropost.last.created_at
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> Wed, 30 Jan 2019 11:45:01 UTC +00:00
>> 
```

最初に更新した日付と最後に更新した日付が出ている。

2:`Micropost.first`を実行した時に発行されるSQL文はどうなっているか？
また、`Micropost.last`の場合はどうなっているか？
　
```ruby
>> Micropost.first
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2019-01-29 07:36:23", updated_at: "2019-01-29 07:36:23">

  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" ORDER BY "microposts"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> #<Micropost id: 4, content: "Lorem ipsum", user_id: 1, created_at: "2019-01-30 11:45:01", updated_at: "2019-01-30 11:45:01">
```

firstの時にASC(昇順)で取り出して、lastの時はDESC(降順)で取り出している。

3:DB上に最初のユーザーを変数userに代入する。
そのuserオブジェクトが最初に投稿したマイクロポストのidはいくつか？
次のdestroyメソッドを使ってそのオブジェクトを削除してみる。

```ruby
>> user = User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "YUUKI", email: "yuukitetsuyanet@gmail.com", created_at: "2019-01-27 11:45:56", updated_at: "2019-01-28 10:06:18", password_digest: "$2a$10$RtF8nSd22GLENhTmlBTkPeaqyPEs9E8v7f3UeR6UecG...", remember_digest: nil, admin: false, ¥: nil, activation_digest: "$2a$10$f3kgl8ZWwRuixqBNDohcb.qkPwxw1Pq2gocBSz116gM...", activated: true, activated_at: "2019-01-27 11:46:05", reset_digest: "$2a$10$cs997A4KK0w9hg0OOW3WA.6cv82z0gw06pZOzIX3x/p...", reset_sent_at: "2019-01-28 10:05:13">
>> user.microposts.first
  Micropost Load (0.1ms)  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-01-29 07:36:23", updated_at: "2019-01-29 07:36:23">

>> user_f = user.microposts.first
  Micropost Load (0.1ms)  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-01-29 07:36:23", updated_at: "2019-01-29 07:36:23">
>> user_f.destroy
   (0.1ms)  begin transaction
  SQL (2.2ms)  DELETE FROM "microposts" WHERE "microposts"."id" = ?  [["id", 1]]
   (6.1ms)  commit transaction
=> #<Micropost id: 1, content: "Lorem ipsum", user_id: 1, created_at: "2019-01-29 07:36:23", updated_at: "2019-01-29 07:36:23">

>> Micropost.find(1)
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
ActiveRecord::RecordNotFound: Couldn't find Micropost with 'id'=1
        from (irb):37
```

##13.2 マイクロポストを表示する

Web経由でマイクロポストを作成する方法は現時点ではない。
しかし、マイクロポストを表示することと、テストすることならできる。

ここでは、Twitterのような独立したマイクロポストを表示する。

以下のモックアップのように、ユーザーshowページで直接マイクロポストを表示させることになる。

ユーザープロフィールにマイクロポストを表示させるため、最初はERbテンプレートを作成する。
次に、サンプルデータ生成タスクにマイクロポストのサンプルを追加して、画面にサンプルデータが表示されるようにする。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/dab79cab-9329-eb8b-1f74-24bf8e69561c.png)

出典：[図 13.4: マイクロポストが表示されたプロフィールページのモックアップ](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

###13.2.1 マイクロポストの描画

ユーザーのプロフィールの画面(show.html.erb)で

- そのユーザーのマイクロポストを表示させたり、
- これまでに投稿した総数も表示させたり

する。

この実装は10章ユーザーを表示する部分と似ている。

演習で既にマイクロポストをいくつか作成しているので、DBをリセットし、サンプルデーターを再生成する。

```ruby
$ rails g controller Microposts
```

今回の目的は、ユーザーごとに全てのマイクロポストを描画できるようにすること。

indexビューでは

```erb:index.html.erb
<ul class="users">
  <%= render @users %>
</ul>
```

Railsは`@users`をUserオブジェクトのリストであると推測する(index.html)

indexでは、`_user.html.erb`パーシャルを使って自動的に`@users`変数内のそれぞれのユーザーを出力していた。

これを参考に、`_micropost.html.erb`パーシャルを使ってマイクロポストのコレクションを表示しようとすると、次のようになる。

```ruby
<ol class="microposts">
  <%= render @microposts %>
</ol>
```

**micropostでは、順序無しリストのulタグではなく、順序付きリストのolタグを使う**

これは、マイクロポストが特定の順序(降順)に依存しているため。

次に、対応するパーシャルを書く。

```erb:_micropost.html.erb
<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content"><%= micropost.content %></span>
  <span classs="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at ) %> ago.
  </span>
</li>
```

ここで`time_ago_in_words`というヘルパーメソッドを使っている。

**これは、「何分前に投稿したか」という情報を文字列で出力するメソッド。*:


また、各マイクロポストに対してCSSのidを割り振っている。

```ruby
<li id="micropost"-<%= micropost.id %>
```

これは一般的に良いとされる慣習だそう。
例えば、将来JavaScriptを使って各マイクロポストを操作したくなった時などに役立つ。


次は、一度に全てのマイクロポストが表示されてしまう潜在的問題に対処する。
10章ではページネーションを使ったが、今回も同じ方法でこの問題を解決する。

前回同様、`will_paginate`メソッドを使うと次のようになる。

```ruby
<%= will_paginate @microposts %>
```

ユーザー一覧画面のコードと比較すると、少し違った。
以前は次のように単純なコードだった。

```ruby
<%= will_paginate %>
```

上記コードは引数なしで動作していたが、これは`will_paginate`が、
Usersコントローラのコンテキストにおいて、@usersインスタンス変数が存在していることを前提としているため。

@usersインスタンス変数は、10賞でも述べたように`ActiveRecord::Relation`クラスのインスタンス。

しかし、今回の場合は**Usersコントローラのコンテキストからマイクロポストをページネーションしたいため**
明示的に@microposts変数を`will_paginate`に渡す必要がある。

したがって、そのようなインスタンス変数をUsersコントローラのshowアクションで定義しなければならない。

```rb:users_controller.rb
  def show
    @user = User.find(params[:id])                                              # paramsで:idパラメータを受け取る(/users/1にアクセスしたら1を受け取る)
    @microposts = @user.microposts.paginate(page: params[:page])                # pageを受け取ってmicropostsに渡して表示する。
    redirect_to root_url and return unless @user.activated?                     # activatedがfalseならルートURLヘリダイレクト
  end
  
```

paginateメソッドはマイクロポストの関連付けを経由してmicropostテーブルに到達し、必要なマイクロポストのページを引き出してくれる。

最後にマイクロポストの投稿数を表示するため、`count`メソッドを使う。

```ruby
user.microposts.count
```

paginateと同様に、関連付けを通してcountメソッドを呼び出すことができる。

countメソッドではDB上のマイクロポストを全部読みだしてから結果の配列に対してlengthを呼ぶ、
と言った無駄な処理はしていない。

↑のような処理だとマイクロポストの数が増加するにつれて効率が低下してしまう。

そうではなく、DB内での計算は高度に最適化されているので、DBに代わりに計算してもらい、特定の`user_id`に紐付いたマイクロポストの数をDBに問い合わせている。

コレで全ての要素が揃ったので、プロフィール画面にマイクロポストを表示させてみる。

```erb:show.html.erb
<% provide(:title, @user.name ) %> <!-- @user.nameを:titleに格納-->
<div class="row">
    <aside class="col-md-4">
        <section class="user_info">
            <h1>
                <%= gravatar_for @user %>                                       <!-- gravatar_forというヘルパーメソッドでユーザー(user)の画像を表示、@userで表示しているビューのユーザー情報を表示 -->
                <%= @user.name %>                                               <!-- 表示しているビューのユーザーの名前(nmae)を表示-->
            </h1>
        </section>
    </aside>
    <div class="col-md-8">
        <% if @user.microposts.any? %>                                         <!-- マイクロポストが空じゃなければ(１つでもあれば)処理を行う-->
        <h3>Microposts (<%= @user.microposts.count %>)</h3>
        <ol class="microposts">
            <%= render @microposts %>                                           <!-- @micropostsページネーションを読み出し-->
        </ol>
        <%= will_paginate @microposts %>
        <% end %>
    </div>
</div>
```

このとき、同様に`if @user.microposts.any?`を使って、ユーザーのマイクロポストが１つもない場合には空のリストを表示させていない点にも注目。

ここで、改良した新しいプロフィール画面をブラウザで見てみる。

![スクリーンショット 2019-01-31 18.25.24.png](https://qiita-image-store.s3.amazonaws.com/0/244639/063eb8c0-c251-6b0e-629a-ff6e2c9796c9.png)


マイクロポストがないため、if文の処理がfalseとなっている。


####演習

1:今回ヘルパーメソッドとして使った`time_ago_in_words`メソッドは、Railsコンソールのhelperオブジェクトから呼び出すことができる。
この`helper`オブジェクトの`time_ago_in_words`メソッドを使って、`3.weeks.ago`や`6.months.ago`を実行してみる。

```ruby
>> helper.time_ago_in_words(3.weeks.ago)
=> "21 days"
>> helper.time_ago_in_words(6.months.ago)
=> "6 months"
```

2:`helper.time_ago_in_words(1.year.ago)`と実行すると、どういった結果が返ってくるか？

```ruby
>> helper.time_ago_in_words(1.year.ago)
=> "about 1 year"
```

3:micropostsオブジェクトのクラスは何か？

```ruby
>> user = User.find(1)
  User Load (0.7ms)  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-01-30 15:05:31", updated_at: "2019-01-30 15:05:31", password_digest: "$2a$10$HCZFOhkJBAIs4/jSiVRaJuc.YW2B5vEBH42caw53axl...", remember_digest: nil, admin: true, activation_digest: "$2a$10$/aa5ShcsDBvnoPQNFk4XD./AAHe97RlhuZwXY.zDzMo...", activated: true, activated_at: "2019-01-30 15:05:31", reset_digest: nil, reset_sent_at: nil>
>> microposts = user.microposts.paginate(page: nil)
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? OFFSET ?  [["user_id", 1], ["LIMIT", 11], ["OFFSET", 0]]
=> #<ActiveRecord::AssociationRelation []>

>> microposts.class
=> Micropost::ActiveRecord_AssociationRelation
```


###13.2.2 マイクロポストのサンプル

ユーザーマイクロポストテンプレートはまだ寂しい見た目なので、サンプルデータ作成タスクにマイクロポストも追加して、この状況を修正する。

全てのユーザーにマイクロポストを追加しようとすると時間が掛かり過ぎるので`take`メソッドを使って最初の6人だけに追加する。

```ruby
User.order(:created_at).take(6)
```


ここで`order`メソッドを使うことで、明示的に最初の6人（昇順ソート）を呼び出すようにしている。


この6人については、1ページの表示限界数＝30
を越えさせるために、それぞれ50個分のマイクロポストを追加するようにしている。

各投稿内容については、`Faker gem`に`Lorem.sentence`という便利なメソッドがあるので、これを使う。

```rb:seeds.rb
users = User.order(:created_at).take(6)
50.times do
  content = Faker::Lorem.sentence(5)
  users.each { |user| user.microposts.create!(content: content) }
end
```

上記のコードで`50.times.do`の`user.each`を後に書いてるのには理由があって、というのもユーザー毎に50個分のマイクロポストを作成してしまうと、ステータスフィードに表示される投稿が全て同じユーザーになってしまい、視覚的な見栄えが悪くなってしまう。

ここで、いつものように開発環境用のDBで再度サンプルデータを生成する。

```ruby
$ rails db:migrate:reset
$ rails db:seed
```

生成し終わったら、一度Railsサーバーを落として、再起動。

ここで、`users_controller.rb`の`showアクション`のredirect_to行を削除。

```rb:users_controller.rb
  def show
    @user = User.find(params[:id])                                              # paramsで:idパラメータを受け取る(/users/1にアクセスしたら1を受け取る)
    @microposts = @user.microposts.paginate(page: params[:page])                # pageを受け取ってmicropostsに渡して表示する。
  end
```


![スクリーンショット 2019-01-31 20.30.25.png](https://qiita-image-store.s3.amazonaws.com/0/244639/69d1e384-e357-ae30-887e-6a68ec99c7aa.png)


マイクロポスト固有のスタイルが与えられていないので、CSSを適用させる。

```scss:custom.scss
/* micrposts */

.microposts {
  list-styles: none;
  padding: 0;
  li {
   padding: 10px 0;
   border-top: 1px solid #e8e8e8;
  }
  .user {
    margin-top: 5em;
    padding-top: 0;
  }
  .content {
    display: block;
    margin-left: 60px;
    img {
      display: block;
      padding: 5px 0;
    }
  }
  .timestamp {
    color: &gray-light;
    display: block;
    margin-left: 60px;
  }
  .gravatar {
    float: left;
    margin-right: 10px;
    margin-top: 5px;
  }
}

aside {
  textarea {
    height: 100px;
    margin-bottom: 5px;
  }
}

span.picture {
  margin-top: 10px;
  input {
    border: 0;
  }
}
```

![スクリーンショット 2019-01-31 20.53.16.png](https://qiita-image-store.s3.amazonaws.com/0/244639/7723d751-28ee-fc9b-5521-4b79b5c7f89e.png)

![スクリーンショット 2019-01-31 20.53.58.png](https://qiita-image-store.s3.amazonaws.com/0/244639/c3e7ab0a-214c-fa70-8a42-5c7b17ddd892.png)

どちらのページでも下部にページネーションリンクを表示している。
1分前・・・などと表示されている部分は、`tie_ago_in_words`メソッドによるもの。

数分待ってからページを再度読み込むと、このテキストは自動的に新しい時間に基づいて更新される。

####演習

1:`(1..10)`.to_a.take(6)というコードの実行結果はどうなるか？

[1,2,3,4,5,6]が表示される。

```ruby
>> (1..10).to_a.take(6)
=> [1, 2, 3, 4, 5, 6]
```

正解。

2:`to_a`メソッドは本当に必要なのか？確かめてみる。

```ruby
>> (1..10).take(6)
=> [1, 2, 3, 4, 5, 6]
>> 
```

必要ない。

3:Fakerはlorem ipsum以外にも、多種多様の事例に対応している。

Fakerドキュメントを眺めながら画面に出力する方法を学び、実際に大学名や電話番号、Hipster IpsumやChuck Norris factsを画面に出力してみる。

```ruby
>> Faker::Hipster.words
=> ["occupy", "organic", "venmo"]
>> Faker::ChuckNorris.fact
=> "When Chuck Norris presses Ctrl+Alt+Delete, worldwide computer restart is initiated."
>> Faker::University.name
=> "Western Durgan"
>> Faker::PhoneNumber.phone_number
=> "200.580.1438 x69164"
>> 
```

###13.2.3 プロフィール画面のマイクロポストをテストする

アカウントを有効化したばかりのユーザーはプロフィール画面にリダイレクトされるので、
そのプロフィール画面が正しく描画されてることは、単体テストを通して確認済み。

この項では、プロフィール画面で表示されるマイクロポストに対して、統合テストを書いていく。
まずは、プロフィール画面用の統合テストを生成してみる。

```ruby
$ rails g integration_test users_profile
Running via Spring preloader in process 18157
      invoke  test_unit
      create    test/integration/users_profile_test.rb
```

プロフィール画面におけるマイクロポストをテストするためには、ユーザーに紐付いたマイクロポストのテスト用データが必要になる。

Railsの慣習に従って、関連付けされたテストデータをfixtureファイルに追加すると、次のようになる。

```ruby
orange:
  content: "I just ate an orange!"
  created_at: <%= 10.minutes.ago %>
  user: michael
```

userにmichaelという値を渡すと、Railsはfixtureファイル内の対応するユーザーを探し出して、もし見つかればマイクロポストに関連付けてくれる。

```ruby
michael:
  name: Michael Example
  email: michael@example.com
```

また、マイクロポストのページネーションをテストするためには、マイクロポスト用のfixtureにいくつかテストデータを追加する必要があるが、コレは埋め込みRubyを使うと簡単。

```ruby
<% 30.times do |n| %>
micropost_<%= n %>
 content: <%= Faker::Lorem.sentence(5) %>
 created_at: <%= 42.days.ago %>
 user: michael
<% end %>
```

コレらのコードを１つにまとめて、マイクロポスト用のfixtureファイル書き出す。

```yml:microposts.yml
orange:
  content: "I just ate an orange!"
  created_at: <%= 10.minutes.ago %>
  user: michael

tau_manifesto:
  content: "Check out the @tauday site by @mhartl: http://tauday.com"
  created_at: <%= 3.years.ago %>
  user: michael

cat_video:
  content: "Sad cats are sad: http://youtu.be/PKffm2ul4dk"
  created_at: <%= 2.hours.ago %>
  user: michael

most_recent:
  content: "Writing a short test"
  created_at: <%= Time.zone.now %>
  user: michael

<% 30.times do |n| %>
micropost_<%= n %>:
 content: <%= Faker::Lorem.sentence(5) %>
 created_at: <%= 42.days.ago %>
 user: michael
<% end %>
```

これでテストデータの準備は完了。

ここで、`users_controller.rb`のshowアクションを元に戻す。

```rb:users_controller.rb
  def show
    @user = User.find(params[:id])                                              # paramsで:idパラメータを受け取る(/users/1にアクセスしたら1を受け取る)
    @microposts = @user.microposts.paginate(page: params[:page])                # pageを受け取ってmicropostsに渡して表示する。
    redirect_to root_url and return unless @user.activated?                     # activatedがfalseならルートURLヘリダイレクト
  end
```

実際のテストでは、プロフィール画面にアクセスした後に

- ページタイトル
- ユーザー名
- Gravatar
- マイクロポストの投稿数
- ページ分割されたマイクロポスト

といった順でテストしていく。

```rb:users_profile_test.rb
require 'test_helper'

class UsersProfileTest < ActionDispatch::IntegrationTest
  include ApplicationHelper
  
  def setup
    @user = users(:michael)
  end
  
  test "profile display" do
    get user_path(@user)
    assert_template 'users/show'
    assert_select 'title', full_title(@user.name)
    assert_select 'h1', text: @user.name
    assert_select 'h1>img.gravatar'
    assert_match @user.microposts.count.to_s, response.body
    assert_select 'div.pagination'
    @user.microposts.paginate(page: 1).each do |micropost|
      assert_match micropost.content, response.body
    end
  end
end
```

Applicationヘルパーを読み込んだことで`full_title`ヘルパーが利用できている点に注目。

上記のテストコードでは、マイクロポストの投稿数をチェックするために、12章の演習で使った`response.body`を使っている。
コレは、そのページの完全なHTML(body全体)を返しているため、そのページのどこかしらにマイクロポストの投稿数が存在するのであれば、

```ruby
assert_match @user.microposts.count.to_s response.body
```

このように、探し出してマッチできる。

これは`assert_select`よりもずっと抽象的なメソッド。

特に`assert_select`ではどのHTMLタグを探すのか伝える必要があるが、
**`assert_match`メソッドではその必要がない点が違う。**

また、assert_selectの引数では、ネストした文法を使っている点にも注目。

```ruby
assert_select 'h1>img_gravatar'
```

このように書くことで、h1タグの内側にある、garavatarクラス付きのimgタグがあるかどうかチェックしている。

これでテストはパスする

```ruby
52 tests, 277 assertions, 0 failures, 0 errors, 0 skips
```

####演習

1:上記テストのh1のテストが正しいか確かめるため、コメントアウトして失敗するか確認。

```erb:show.html.erb
            <!--<h1>-->
                <%= gravatar_for @user %>                                       <!-- gravatar_forというヘルパーメソッドでユーザー(user)の画像を表示、@userで表示しているビューのユーザー情報を表示 -->
                <%= @user.name %>                                               <!-- 表示しているビューのユーザーの名前(nmae)を表示-->
            <!--</h1>-->
```

```ruby
 FAIL["test_profile_display", UsersProfileTest, 0.9884029359998294]
 test_profile_display#UsersProfileTest (0.99s)
        Expected at least 1 element matching "h1", found 0..
        Expected 0 to be >= 1.
        test/integration/users_profile_test.rb:14:in `block in <class:UsersProfileTest>'

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

Finished in 1.27827s
21 tests, 127 assertions, 1 failures, 0 errors, 0 skips
```

2:テストを変更して、`will_paginate`が一個のみ表示されていることをテストしてみる。

```ruby
  test "profile display" do
    get user_path(@user)
    assert_template 'users/show'
    assert_select 'title', full_title(@user.name)
    assert_select 'h1', text: @user.name
    assert_select 'h1>img.gravatar'
    assert_match @user.microposts.count.to_s, response.body
    assert_select 'div.pagination', count: 1
    @user.microposts.paginate(page: 1).each do |micropost|
      assert_match micropost.content, response.body
    end
  end
end
```


##13.3 マイクロポストを操作する

データモデリングとマイクロポスト表示テンプレートの両方が完成したので、
次はWeb経由でそれらを作成する為のインターフェイスに取り掛かる。

まずステータスフィードの開発に取り掛かり、最後にユーザーがマイクロポストをWeb経由で破棄できるようにする。


従来のRails開発と異なる点が一点ある。
Micropostsリソースへのインターフェイスは、主にプロフィールページとHomeページのコントローラを経由して使うので、new(新規作成)やedit(編集)のようなアクションは不要である。

つまり、create(ユーザー新規作成)、destroy(削除)アクションがあれば十分。

上記を考慮してMicropostsリソースは以下のように出来上がる。

```rb:routes.rb
Rails.application.routes.draw do
  root 'static_pages#home'
  get     '/help',    to: 'static_pages#help'
  get     '/about',   to: 'static_pages#about'
  get     '/contact', to: 'static_pages#contact'
  get     '/signup',  to: 'users#new'
  post    '/signup',  to: 'users#create'
  get     '/login',   to: 'sessions#new'
  post    '/login',   to: 'sessions#create'
  delete  '/logout',  to: 'sessions#destroy'
  resources :users                                                              # usersリソースをRESTfullな構造にするためのコード。
  resources :account_activations, only: [:edit]                                 # editアクションのみaccount_activationsリソースを適用
  resources :password_resets,     only: [:new, :create, :edit, :update]         # password再設定用のリソースを適用
  resources :microposts,          only: [:create, :destroy]                     # micropostsリソースをcreateとdestroyアクションにのみ適用
end
```

###13.3.1 マイクロポストのアクセス制御

Micropostsリソースの開発では、Micropostsコントローラ内のアクセス制御から始めることにする。

関連付けられたユーザーを通してマイクロポストにアクセスするので、`create`アクションや`destroy`アクションを利用するユーザーは、ログイン済みでなければならない。

ログイン済みかどうかを確かめるテストでは、Usersコントローラ用のテストがそのまま役に立つ。

つまり、正しいリクエストを各アクションに向けて発行し、マイクロポストの数が変化していないかどうか、また、リダイレクトされるかどうかを確かめればよい。

```rb:microposts_controller_test.rb
require 'test_helper'

class MicropostsControllerTest < ActionDispatch::IntegrationTest

  def setup
    @micropost = microposts(:orange)
  end
  
  test "should redirect create when not logged in" do
    assert_no_difference "Micropost.count" do
      post microposts_path, params: { micropost: { content: "Lorem ipsum"} }
    end
    assert_redirected_to login_url
  end
  
  test "should redirect destroy when not logged in" do
    assert_no_difference 'Micropost.count' do
      delete micropost_path(@micropost)
    end
    assert_redirected_to login_url
  end
end
```

上記のテストにパスするコードを書くためには、少しアプリケーション側のコードをリファクタリングしておく必要がある。

それは、beforeフィルターの`logged_in_user`メソッドを使って、ログインを要求したことについて思い出すとわかる。

あの時はUsersコントローラ内にこのメソッドがあったので、beforeフィルターで指定したが、このメソッドはMicropostsコントローラでも必要。

そこで、各コントローラが継承するApplicationコントローラに、`logged_in_user`(ユーザーログインの確認)メソッドを移して、
**共通で`beforeフィルター`を使えるようにする。**

```rb:application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  include SessionsHelper                                                        #SessionHelper(メソッドの集合体)を全コントローラに適用
  
  private
  
    # ユーザーのログインを確認する
    def logged_in_user
      unless logged_in?
       store_location
       flash[:danger] = "Please log in."
       redirect_to login_url
      end
    end
end
```

`users_controller.rb`から、`logged_in_user`を削除する。

```users_controller.rb
class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy]       # logged_in_userメソッドを適用

  private                                                                       # 外部から使えない（Usersコントローラ内のみ）部分
  
    def user_params                                                             # paramsハッシュの中を指定する。（requireで:user属性を必須、permitで各属性の値が入ってないとparamsで受け取れないよう指定）
      params.require(:user).permit(:name, :email, :password,
                                  :password_confirmation)
    end
    
    # beforeアクション
```

アクションを移したことにより、Micropostsコントローラからも`logged_in_user`メソッドを呼び出せるようになった。

これにより、`create`アクションや`destroy`アクションにログインしていないと処理を実行できないアクセス制限を簡単に掛けるようになった。

```rb:microposts_controller.rb
class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]                      # ログインユーザーのみ作成したり削除できるよう適用
  
  def create
    
  end
  
  def destroy
    
  end
end
```

これでテストはパスする。

```ruby
54 tests, 281 assertions, 0 failures, 0 errors, 0 skips
```

####演習

1:なぜUsersコントローラ内にある`logged_in_user`フィルターは残したままにするとマズイのか？

無駄なコードが増えたり、エラーの原因になるから。


###13.3.2 マイクロポストを作成する

7章では、HTTP POSTリクエストをUsersコントローラのcreateアクションに発行するHTMLフォームを作成することで、ユーザーのサインアップを実装した。

マイクロポスト作成の実装もこれと似ていて、
主な違いは別のmicropost/newページを使う代わりに、**ホーム画面(home.html.erb)にフォームを置くという点。**

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/fa46cccd-6e3d-47f4-29df-8a7af8299523.png)


出典：[図 13.10: マイクロポスト作成フォームのあるホーム画面のモックアップ](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

最後にホーム画面を実装したときは、[sign up now!]ボタンが中央にあった。

要は、ユーザーがログインしている場合のみ、マイクロポスト作成フォームを表示させるようにする。
(ホーム画面の表示を、ログイン状態と日ログイン状態で変わるよう実装する。)


その前に、まずはマイクロポストのcreateアクションを作り始める。

このアクションもユーザー用アクションと似ていて、違う点は
**新しいマイクロポストをbulidするためにUser/Micropost関連付けを使っている点。**

```rb:microposts_controller.rb
class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]                      # ログインユーザーのみ作成したり削除できるよう適用
  
  def create
    @micropost = current_user.microposts.build(micropost_params)                # formで送った値をmicropost_paramsで受け取り、親モデルと関連付け(bulid)してcurrent_userに渡して代入
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      render 'static_pages/home'
    end
  end
  
  def destroy
    
  end
  
  private
  
    def micropost_params
      params.require(:micropost).permit(:content)
    end
end
```

`micropost_params`でStrong Parametersを使っていることにより、
**マイクロポストのcontent属性だけがWeb経由で変更可能になっている点に注目。**


次に、フォームを作成する。

マイクロポスト作成フォームを構築するために、
サイト訪問者がログインしているかどうかに応じて異なるHTMLを提供するコードを使う。

```erb:home.html.erb
<% if logged_in? %>
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
  </div>
<% end %>

<div class="center jumbotron">
  <h1>YUUKIのポートフォリオサイトへようこそ</h1>

  <h2>
    このサイトは
    <a href="https://twitter.com/bitcoinjpnnet">YUUKI</a>
    のポートフォリオサイトです
  </h2>

  <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>

<%= link_to image_tag("yuuki.png", alt: "Rails logo"),
            'https://twitter.com/bitcoinjpnnet', target: "_blank" %>
```

上記コードで条件式でログインしている場合のみ、

- ユーザー情報(shared/user_info)
- マイクロポストフォーム(shared/micropost_form)

をパーシャルとして描画させる。

この２つのパーシャルはまだ書いていないので、まずはuser_infoから書いていく。

```erb:_user_info.html.erb
<%= link_to gravatar_for(current_user, size: 50), current_user %>
<h1><%= current_user.name %></h1>
<span><%= link_to "view my profile", current_user %></span>
<span><%= pluralize(current_user.microposts.count, "micropost") %></span>       <!-- カウントした数によってmicropostのスペルを変更する -->
```

プロフィールサイドバーのときと同様、
ユーザー情報にもユーザーが投稿したマイクロポストの総数が表示されていることにも注目。

プロフィールサイドバーでは、`1 micropost`や`2 microposts`というように、
**ユーザーの投稿数に合わせてスペルを追従させたいので、`pluralize`メソッドを使って調整している。**


次はマイクロポスト作成フォームを定義する。
これはユーザー登録フォームに似ている。

```erb:_micropost_form.html.erb
<%= form_for(@micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
```

上記のフォームが動くようにするためには、2箇所の変更が必要。

１つは、**関連付けを使って@micropostを定義する**

```ruby
@micropost = current_user.microposts.bulid
```

上記コードをコントローラに埋め込む。


```rb:static_pages_controller.rb
class StaticPagesController < ApplicationController
  
  def home
    @micropost = current_user.microposts.build if logged_in?                    # ログインしていたらcurrent_userに紐付いたマイクロポストオブジェクトを生成し代入
  end
```

もちろんcurrent_userメソッドはユーザーがログインしている時しか使えない。
**したがって、@micropost変数もログインしているとき定義されるようになる。**


さらに、もう１つの変更は**エラーメッセージのパーシャルを再定義すること**

でなければ

```ruby
<%= render 'shared/error_messages', object: f.object %>
```

このコードが動かない。

7章ではエラーメッセージパーシャルが@user変数を直接参照していた。
今回は代わりに@microposts変数を使う必要がある。

これらのケースをまとめると、フォーム変数fを`f.object`とすることによって、関連付けられたオブジェクトにアクセスすることができる。したがって、

```ruby
form_for(@user) do |f|
```

上記のように、f.objectが@userを引数に取る場合と

```ruby
form_for(@micropost) do |f|
```

f.objectが@micropostになる場合がある。

パーシャルにオブジェクトを渡すために、
**値がオブジェクトで、キーがパーシャルでの変数名と同じハッシュを利用する。**

これで、error_messagesパーシャルの2行目のコードが完成する。

`object: f.object`は`error_messages`パーシャルの中で
**objectという変数名を作成してくれるので、この変数を使ってエラーメッセージを更新すればよいということ。**

簡単にいうと、エラーメッセージ用の変数をobject変数に統一し、renderの読み出し時にobjectがエラーであれば(送信出来なければ)、全てを`object: f.object`でエラーを表示させる。

```erb:_error_messages.html.erb
<% if object.errors.any? %>                                                      <!-- オブジェクトのエラーメッセージが空だった（エラーを起こしていない)場合true -->
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(object.errors.count, "error") %>.
    </div>
    <ul>
      <%= object.errors.full_messages.each do |msg| %>                          <!-- エラーメッセージの配列をブロック変数msgに繰り返し代入 -->
      <li><%= msg %></li>                                                       <!-- ブロック変数msgを表示（エラー文の値を一つ一つ表示） -->
      <% end %>
    </ul>
  </div>
<% end %>
```

この時点でテストは失敗する。

```ruby
54 tests, 267 assertions, 0 failures, 2 errors, 0 skips
```

これは`error_messages`パーシャルが

- ユーザー登録
- パスワード設定
- ユーザー編集

それぞれのビューで使われていたため、これらで第二引数に`object: f.object`と更新する必要がある。

```erb:_form.html.erb
    <!--ボタンと画像を表示-->

    <div class="row">
      <div class="col-md-6 col-md-offset-3">
    <!-- formの送信先を指定 -->
    
    <%= form_for(@user, url: yield(:url)) do |f| %>                             <!-- 、fブロックに代入-->
      <%= render 'shared/error_messages', object: f.object %>                   <!-- エラーメッセージ用のパーシャルを表示 -->

    <!-- form作成-->
```

```erb:password_resets/edit.html.erb
<% provide(:title, 'Reset password') %>
<h1>Reset password</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
   <%= form_for(@user, url: password_reset_path(params[:id])) do |f| %>
    <%= render 'shared/error_messages', object: f.object %>
    
    <%= hidden_field_tag :email, @user.email %>
```

`new.html.erb`と`users/edit.html.erb`ではformパーシャルを使っていたので、
`_form.html.erb`と`password_resets/edit.html.erb`の２ファイルを修正するだけでOK。

これでテストはパスする。

```ruby
54 tests, 281 assertions, 0 failures, 0 errors, 0 skips
```

これで全てのHTMLが適切に表示されるようになったので、実際にフォームを見て確認する。

![スクリーンショット 2019-02-01 23.28.44.png](https://qiita-image-store.s3.amazonaws.com/0/244639/2914a843-7de5-2428-bd8c-3ec18c87a0b4.png)

![スクリーンショット 2019-02-01 23.30.15.png](https://qiita-image-store.s3.amazonaws.com/0/244639/3dd8e162-3f30-d0f9-4614-2178d2f96aeb.png)


###演習

1:Homeページをリファクタリングして、`if-else`文の分岐のそれぞれに対してパーシャルを作ってみる。

```erb:home.html.erb
<% if logged_in? %>
  <%= render 'static_pages/if' %>
<% else %>
  <%= render 'static_pages/else' %>
<% end %>
```

```erb:_if.html.erb
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
  </div>
```

```erb:_else.html.erb
<div class="center jumbotron">
  <h1>YUUKIのポートフォリオサイトへようこそ</h1>

  <h2>
    このサイトは
    <a href="https://twitter.com/bitcoinjpnnet">YUUKI</a>
    のポートフォリオサイトです
  </h2>

  <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>

<%= link_to image_tag("yuuki.png", alt: "Rails logo"),
            'https://twitter.com/bitcoinjpnnet', target: "_blank" %>
```


###13.3.3 フィードの原型

マイクロポスト投稿フォームが動くようになったが、今の段階では投稿した内容をすぐに見ることが出来ない。
というのも、Homeページにまだマイクロポストを表示する部分が実装されていないから。

実際に正しく動いているか確認するには、エントリーを投稿後にプロフィールページに移動してポストを確認すればよいが、これはかなり面倒な作業。

以下のモックアップのような、ユーザー自身のポストをHomeに載せた方が便利なので、これを実装する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/631573fa-20d9-cdd7-1ba4-0bf264cc57d1.png)

出典：[図 13.13: 試作フィードがあるHomeページのモックアップ](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

全てのユーザーがフィードを持つので、feedメソッドはUserモデルで作るのが自然。
なお、次章で完全なフィードを実装するため、`where`メソッドを使う。

**まずは現在ログインしているユーザーのマイクロポストをすべて取得してくる。**

```rb:user.rb
  def feed
    Micropost.where("user_id = ?", id)
  end
  
private
```

上の疑問符があることで、**SQLクエリに代入する前にidがエスケープされるため、**
SQLインジェクション攻撃の対象となるようなセキュリティホールを避けることができる。

この場合のid属性は単なる整数であるため危険はないが、
**SQL文に変数を代入する場合は常にエスケープする習慣を身に付けておくべき。**

また、本質的には

```ruby
def feed
  microposts
end
```

このコードと同じだが（マイクロポストを表示する上では）
上のコードを使わなかったのは、14章で必要となる完全なステータスフィードで応用が効くため。


アプリケーションでフィードを使うために、以下の流れで実装する。

①現在のユーザーのページ分割されたフィードに@feed_itemsインスタンス変数を追加
②フィード用のパーシャルをHomeページに追加

Homeページに変更を加える時、ユーザーがログインしているかどうかを調べる後置if文を、前置if文に変更する。

```ruby
@microopost = current_user.microposts.build if logged_in?
```

これを

```ruby
  if logged_in?
    @micropost = current_user.microposts.bulid
    @feed_items = current_user.feed.paginate(page: params[:page])
  end
```

**1行で終わる場合は後置if文、2行以上の時は前置if文を使うのがRubyの慣習**


```rb:static_pages_controller.rb
  def home
    if logged_in?
      @micropost  = current_user.microposts.build                               # current_userに紐付いたマイクロポストオブジェクトを生成し代入
      @feed_items = current_user.feed.paginate(page: params[:page])             # current_userに紐付いたポストをページネーション化して代入
    end
  end
```

```erb:_feed.html.erb
<% if @feed_items.any? %>
  <ol class="microposts">
    <%= render @feed_items %>
  </ol>
  <%= will_paginate @feed_items %>
<% end %>
```

上記がステータスフィードのパーシャル。
Micropostのパーシャルとは少し異なっている。

```ruby
<%= render @feed_items %>
```

`@feed_items`の各要素がMicropostクラスを持っていたため、
RailsはMicropostのパーシャルを呼び出すことができる。

このように、
**Railsは対応する名前のパーシャルを、渡されたリソースのディレクトリ内から探しにいくことができる。**

```ruby
app/views/microposts/_micropost.html.erb
```

結果的に上記ファイルのパーシャル(各ポスト投稿)を呼び出している。


あとは、_feedパーシャルをHomeページに組み込むことで、
フィードとして表示することができる。

先ほどifパーシャルを使ったので、こちらに組み込む。

```erb:_if.html.erb
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
    <div class="col-md-8">
      <h3>Micropost Feed</h3>
      <%= render 'shared/feed' %>
    </div>
  </div>
```

これでOK

![スクリーンショット 2019-02-02 2.29.40.png](https://qiita-image-store.s3.amazonaws.com/0/244639/1c51df2d-2778-c8e8-15e1-5b335a4dcb3e.png)

ただ、現時点ではマイクロポストの投稿が失敗すると、Homeページは`@feed_items`インスタンス変数を期待しているため、エラーとなる。
これを簡単に解決するため、`@feed_items`に空の配列を代入する。

```rb:microposts_controller.rb
  def create
    @micropost = current_user.microposts.build(micropost_params)                # formで送った値をmicropost_paramsで受け取り、親モデルと関連付け(bulid)してcurrent_userに渡して代入
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end
```

####演習

1:新しく実装したマイクロポストの投稿フォームを使って、実際にマイクロポストを投稿してみる。
Railsサーバーのログ内にあるINSERT文では、どういった内容をDBに送っているか？

```ruby
   (0.0ms)  begin transaction
  SQL (1.8ms)  INSERT INTO "microposts" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["content", "こんにちは"], ["user_id", 1], ["created_at", "2019-02-01 18:41:52.457876"], ["updated_at", "2019-02-01 18:41:52.457876"]]
   (6.8ms)  commit transaction
```

2:コンソールを開き、user変数にDB上の最初のユーザーを代入。
その後、
Micropost.where("user_id = ?", user.id)
`user.microposts`
`user.find`

をそれぞれ実行してみて、実行結果が全て同じあることを確認。

```ruby
>> user = User.first
>> user_where = Micropost.where("user_id = ?", user.id)
>> user_microposts = user.microposts
>> user_feed = user.feed
>> user_where == user_microposts
=> true
>> user_microposts == user_feed
=> true
```

全部同じ。

###13.3.4 マイクロポストを削除する

最後の機能として、マイクロポストリソースにポストを削除する機能を追加する。

これは、ユーザー削除と同様に`delete`リンクで実現する。

ユーザーの削除は管理者ユーザーのみが行えるよう制限されていたのに対し、
今回は**自分が投稿したマイクロポストに対してのみ削除リンクが動作するようにする。**

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/a422cb09-197e-e9d8-dbb2-70ba3ba5fbea.png)

出典：[図 13.16: マイクロポストの削除リンクと試作フィードのモックアップ](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

最初のステップとして、マイクロポストのパーシャルに削除リンクを追加する。

```erb:_micropost.html.erb
<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content"><%= micropost.content %></span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
  <% if current_user?(micropost.user) %>
    <%= link_to "delete", micropost, method: :delete,
                                    data: { confirm: "You sure?" } %>
  <% end %>
  </span>
</li>
```

次に、Micropostsコントローラのdestroyアクションを定義する。

これもユーザーにおける実装とだいたい同じで、
大きな違いは、`admin_user`フィルターで@user変数を使うのではなく、
関連付けを使ってマイクロポストを見つけようとしている点。

これにより、あるユーザーが他のユーザーのマイクロポストを削除しようとすると、自動的に失敗するようになる。

具体的には、`correct_user`フィルター内でfindメソッドを呼び出すことで、
現在のユーザーが削除対象のマイクロポストを保有しているかどうか確認する。

```rb:microposts_controller.rb
class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]                      # ログインユーザーのみ作成したり削除できるよう適用
  before_action :correct_user,   only: :destroy
  
  def create
    @micropost = current_user.microposts.build(micropost_params)                # formで送った値をmicropost_paramsで受け取り、親モデルと関連付け(bulid)してcurrent_userに渡して代入
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end
  
  def destroy
    @micropost.destroy
    flash[:success] = "Micropost deleted"
    redirect_to request.referrer || root_url
  end
  
  private
  
    def micropost_params
      params.require(:micropost).permit(:content)
    end
    
    def correct_user
      @micropost = current_user.microposts.find_by(id: params[:id])
      redirect_to root_url if @micropost.nil?
    end
end
```

上記では`destroy`メソッドでリダイレクトを使っている点に注目。


```ruby
request.referrer || root_url
```

ここでは`request.referrer`というメソッドを使っている。

このメソッドはフレンドリーフォワーディングの`request.url`変数と似ていて、１つ前のURLを返す。
(今回の場合はHomeページになる)

このため、マイクロポストがHomeページから削除された場合でもプロフィールページから削除された場合でも、
**`request.referrer`を使うことでDELETEリクエストが発行されたページに戻すことができる。**

元に戻すURLが見つからなかった場合でも、`root_url`を||で指定しているので、エラーが出ずに/へと飛ぶ。

これらのコードにより、上から2番目のマイクロポストを削除してみると、エラーが出ずに削除できているのが分かる。

![スクリーンショット 2019-02-02 14.28.01.png](https://qiita-image-store.s3.amazonaws.com/0/244639/561ea2e0-53cb-093b-8b87-0370054c6a4a.png)

####演習

1:マイクロポストを作成し、その後、作成したマイクロポストを削除してみる。
また、Railsサーバーのログを見てみて、DELETE文の内容を確認してみる。

```ruby
   (0.1ms)  begin transaction
  SQL (1.0ms)  DELETE FROM "microposts" WHERE "microposts"."id" = ?  [["id", 306]]
   (7.0ms)  commit transaction
```

2:`redirect_to request.referrer || root_url`の行を
`redirect_back(fallback_location: root_url)`と置き換えてもうまく動くことをブラウザを使って確認する。

```rb:microposts_controller.rb
  def destroy
    @micropost.destroy
    flash[:success] = "Micropost deleted"
    redirect_back(fallback_location: root_url)
  end
```

確認済み。

###13.3.5 フィード画面のマイクロポストをテストする

13.3.4のコードで、Micropostモデルとそのインターフェースが完成した。

残っている箇所は

- Micropostsコントローラの許可をチェックするテスト
- それらをまとめる統合テスト


まずはマイクロポスト用のfixtureに、別々のユーザーに紐付けられたマイクロポストを追加していく。


```yml:microposts.yml
ants:
  content: "yes yes,"
  created_at: <%= 2.years.ago %>
  user: archer

zone:
  content: "Danger zone!"
  created_at: <%= 3.days.ago %>
  user: archer

tone:
  content: "oh"
  created_at: <%= 10.minutes.ago %>
  user: lana

van:
  content: "Dude"
  created_at: <%= 4.hours.ago %>
  user: lana
```

次に、自分以外のユーザーのマイクロポストを削除しようとすると、
適切にリダイレクトされることをテストで確認する。

```rb:microposts_controller_test.rb
  test "should redirect destroy for wrong micropost" do
    log_in_as(users(:michael))
    micropost = microposts(:ants)
    assert_no_difference 'Micropost.count' do
      delete micropost_path(micropost)
    end
    assert_redirected_to root_url
  end
```

最後に統合テストを書く。

統合テストでは、

- ログイン
- マイクロポストのページ分割の確認
- 無効なマイクロポストを投稿
- 有効なマイクロポストを投稿
- マイクロポストの削除
- 他のユーザーのマイクロポストには[delete]リンクが表示されないことを確認

この順でテストしていく。

まずは統合テストを生成する

```ruby
$ rails g integration_test microposts_interface
Running via Spring preloader in process 8155
      invoke  test_unit
      create    test/integration/microposts_interface_test.rb
```

実際の統合テストを書く。

```rb:microposts_interface_test.rb
require 'test_helper'

class MicropostsInterfaceTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end
  
  test "micropost interface" do
    log_in_as(@user)
    get root_path
    assert_select 'div.pagination'
    # 無効な送信
    assert_no_difference 'Micropost.count' do
      post microposts_path, params: { micropost: { content: "" } }
    end
    assert_select 'div#error_explanation'
    # 有効な送信
    content = "This micropost really ties the room together"
    assert_difference 'Micropost.count', 1 do
      post microposts_path, params: { micropost: { content: content } }
    end
    assert_redirected_to root_url
    follow_redirect!
    assert_match content, response.body
    # 投稿を削除する
    assert_select "a", text: 'delete'
    first_micropost = @user.microposts.paginate(page: 1).first
    assert_difference 'Micropost.count', -1 do
      delete micropost_path(first_micropost)
    end
    # 違うユーザーのプロフィールにアクセス(削除リンクがないことを確認)
    get user_path(users(:archer))
    assert_select 'a', text: "delete", count: 0
  end
end
```

これでテストはパスする。

```ruby
1 tests, 10 assertions, 0 failures, 0 errors, 0 skips
```

####演習

1:上記テストが正しく動いているか、それぞれ対応するコードをコメントアウトして失敗するか確認。

確認済み。

2:サイドバーにあるマイクロポストの合計投稿数をテストしてみる。

また、単数形なら`micropost`複数形なら`microposts`が正しく表示されているかどうかもテストする。

```rb:microposts_interface_test.rb
  test "micropost sidebar count" do
    log_in_as(@user)
    get root_path
    assert_match "#{@user.microposts.count} microposts", response.body
    # まだマイクロポストを投稿していないユーザー
    other_user = users(:malory)
    log_in_as(other_user)
    get root_path
    assert_match "0 microposts", response.body
    other_user.microposts.create!(content: "A micropost")
    get root_path
    assert_match "1 micropost", response.body
  end
```

##13.4 マイクロポストの画像投稿

ここまででマイクロポストに関する基本的な操作は全て実装できた。

あとは応用として画像付きマイクロポストを投稿できるようにする。

その手順として

- 開発環境用のβ版を実装
- いくつかの改善をとおして本番環境用の完成版を実装

で行う。

画像アップロード機能を追加するためには、以下の視覚的な要素が必要。

- 画像をアップロードするためのフォーム
- 投稿された画像そのもの

この２つの要素を満たしたモックアップはこちら

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/0224dcf5-1cb7-e857-f0c1-2bfe32739efa.png)

出典：[図 13.18: 画像付きマイクロポストを投稿したときのモックアップ
](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

Upload Imageボタンで画像付きマイクロポストを投稿できるようにする。


###13.4.1 基本的な画像アップロード

投稿しt画像を扱ったり、Micropostモデルと関連付けするために、今回は
`CarrierWave`という画像アップローダーを使う。

まずは`carrierwave gem`をGemfileに追加する。

併せて`mini_magick gem`と`fog gems`も含める。

これらのgemは画像をリサイズしたり、本番環境で画像をアップロードするために使う。

```Gemfile
gem 'faker',        '1.7.3'
gem 'carrierwave',  '1.2.2'

group :production do
  gem 'pg', '0.20.0'
  gem 'fog','1.42'
end
```

いつも通りgemをインストール

```ruby
$ bundle install
```

Carrier Waveを導入すると、Railsのジェネレーターで画像アップローダーが生成できるようになる。
次のコマンドを実行して適用する。

```ruby
rails g uploader Picture
```

Carrier Waveでアップロードされた画像は、Active Recordモデルの属性と関連付けされているべき。
関連付けされる属性には画像のファイル名が格納されるため、pictureのデータ型は`string`型にしておく。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/564fba46-336e-03d7-c6d0-4cd1c96bb379.png)

出典：[図 13.19: picture属性を追加したマイクロポストのデータモデル](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

必要となるpicture属性をMicropostモデルに追加するために、
マイグレーションファイルを生成し、開発環境のDBに適用する。

```ruby
$ rails g migration add_picture_to_microposts picture:string
$ rails db:migrate
```

CarrierWaveに画像と関連付けたモデルを伝えるためには、`mut_uploader`というメソッドを使う。

このメソッドは、引数に属性名のシンボルと生成されたアップローダーのクラス名を取る。

```ruby
mount_uploader :picture, PictureUploader #pictureにPictureUploaderのクラス名を渡す
```

`picture_uploader.rb`というファイルで`PictureUploader`クラスが定義されている。

Micropostモデルにアップローダーを追加した結果がこちら

```rb:micropost.rb
class Micropost < ApplicationRecord
  belongs_to :user
  default_scope -> { order(created_at: :desc) }                                 # 並び順を降順に変更
  mount_uploader :picture, PictureUploader                                      # picture属性にPictureUploader（画像投稿gem）を渡す。
  validates :user_id, presence: true
  validates :content, presence: true, length: { maximum: 140 }
end
```

Homeページにアップローダーを追加するためには、マイクロポストのフォームに`file_field`タグを含める必要がある。

```erb:_micropost_form.html.erb
<%= form_for(@micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
  <span class="picture">
    <%= f.file_field :picture %>
  </span>
<% end %>
```

最後に、Webから更新できる許可リストにpicture属性を追加する。
追加すると、`micropost_params`メソッドは以下のようになる。

```rb:microposts_controller.rb
  private
  
    def micropost_params
      params.require(:micropost).permit(:content, :picture)                     # pictureとcontentをmicropostハッシュの許可された属性のリストに追加する
    end
```

マイクロポスト用のパーシャルにimage_tagヘルパーで画像を埋め込む。

```erb:_micropost.html.erb
<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content">
    <%= micropost.content %>
    <%= image_tag micropost.picture.url if micropost.picture? %>
  </span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
  <% if current_user?(micropost.user) %>
    <%= link_to "delete", micropost, method: :delete,
                                    data: { confirm: "You sure?" } %>
  <% end %>
  </span>
</li>
```

一度画像がアップロードされれば、Micropostパーシャルの`image_tag`ヘルパーでその画像を描画できるようになる。

また、画像の無いマイクロポストでは画像を表示させないようにするために、
`picture?`という論理値を返すメソッドを使っている点に注目。

このメソッドは、
**画像用の属性名に応じて、CarrierWave**が自動的に生成してくれるメソッド。

![スクリーンショット 2019-02-02 17.49.21.png](https://qiita-image-store.s3.amazonaws.com/0/244639/72848caf-dd66-3dc7-2ddd-835ffe9ae136.png)

####演習

1:画像付きのマイクロポストを投稿してみる。大きすぎる画像が表示されればOK.

確認済み。

2:画像アップローダーをテストしてみる。
テストの準備として、まずはサンプル画像をfixtureディレクトリに追加する。

```ruby
$ cp app/assets/images/rails.png test/fixtures/
```

実際のテストでは、Homeページにあるファイルアップロードと、
投稿に成功した時に画像が表示されているかどうかをチェックする。



```rb:microposts_interface_test.rb
  test "micropost interface" do
    log_in_as(@user)
    get root_path
    assert_select 'div.pagination'
    assert_select 'input[type=file]'
    # 無効な送信
    assert_no_difference 'Micropost.count' do
      post microposts_path, params: { micropost: { content: "" } }
    end
    assert_select 'div#error_explanation'
    # 有効な送信
    content = "This micropost really ties the room together"
    picture = fixture_file_upload('test/fixtures/rails.png', 'image/png')
    assert_difference 'Micropost.count', 1 do
      post microposts_path, params: { micropost: 
                                    { content: content, 
                                      picture: picture } }
    end
    assert assigns(:micropost).picture?
    follow_redirect!
    assert_match content, response.body
    # 投稿を削除する
    assert_select "a", text: 'delete'
    first_micropost = @user.microposts.paginate(page: 1).first
    assert_difference 'Micropost.count', -1 do
      delete micropost_path(first_micropost)
    end
    # 違うユーザーのプロフィールにアクセス(削除リンクがないことを確認)
    get user_path(users(:archer))
    assert_select 'a', text: "delete", count: 0
  end
```

###13.4.2 画像の検証

先ほどのアップローダーではいくつかの欠点がある。
例えば、アップロードされた画像に対する制限がないため、もしユーザーが巨大なファイルを上げたり、無効なファイルを上げると問題が発生してしまう。

この欠点を直すために、
**画像サイズやフォーマットに対するバリデーションを実装し、
サーバー用途クライアント用の両方に追加する**

最初のバリデーションでは、有効な画像の種類を制限していくが、
これはCarrierWaveのアップローダーの中に既にヒントがある。

生成されたアップローダーの中にコメントアウトされたコードがあるので、
このコメントアウトを取り消すことで、画像のファイル名から有効な拡張子(PNG/GIF/JPEG)を検証することができる。

```rb:picture_uploader.rb
  # アップロード可能な拡張子のリスト
  def extension_whitelist
    %w(jpg jpeg gif png)
  end
```


2つ目のバリデーションでは、画像のサイズを制御する。

これは`Micropost`モデルに書き足していく。

先ほどのバリデーションと異なり、
**ファイルサイズに対するバリデーションはRailsの既存のオプション(presenceやlengthなど)には無い。**

したがって、手動で`picture_size`というバリデーションを定義する。

このバリデーションでは`validates`ではなく`validate`とsを抜かしたメソッドを使用する。

```rb:micropost.rb
class Micropost < ApplicationRecord
  belongs_to :user
  default_scope -> { order(created_at: :desc) }                                 # 並び順を降順に変更
  mount_uploader :picture, PictureUploader                                      # picture属性にPictureUploader（画像投稿gem）を渡す。
  validates :user_id, presence: true
  validates :content, presence: true, length: { maximum: 140 }
  validate :picture_size
end

  private

    # アップロードされた画像のサイズをバリデーションする
    def picture_size
      if picture.size > 5.megabytes
        errors.add(:picture, "should be less than 5MB")
      end
    end
```

引数にシンボル(:picture_size)を取り、そのシンボル名に対応したメソッドを呼び出す。
また、呼び出す`picture_size`メソッドでは、5MB上限とし、
それを超えた場合はカスタマイズしたエラーメッセージを`errors`コレクションに追加。

定義した画像のバリデーションビューに組み込むために、
クライアント側に２つの処理を追加する。

まずはフォーマットのバリデーションを反映するためには、`file_field`タグにacceptパラメータを付与した使う。

```ruby
<%= f.file_field :picture, accept: 'image/jpeg,image/git,image/png' %>
```

このとき`accept`パラメータでは、許可したファイル形式を、`MIMEタイプ`で指定するようにする。

次に、大きすぎるファイルサイズに対して警告を出すために、
ちょっとしたJavaScript（正確にはjQuery）を書き加える。

こうすることで、
**長すぎるアップロード時間を防いだり、サーバーへの負荷を抑えたりすることに繋がる。**

```ruby
$('#micropost_picture').bind('change', function() {
 var size_in_megabytes = this.files[0].size/1024/1024;
 if (size_in_megabytes > 5) {
   alert('Maximum file size is 5MB. Please chooose a smailler file.'); 
 } 
});
```

上のコードではCSS id　のmicropost_pictureを含んだ要素を見つけ出し、この要素を監視している。
そして、このidを持った要素とは、マイクロポストのフォームを指す。

つまり、このCSS idを持つ要素が変化した時、このjQueryの関数が動き出す。

そして、もしファイルサイズが大きすぎた場合、alertメソッドで警告を出すといった仕組み。

これらの追加的なチェック機能を以下に書き出す。

```erb:_micropost_form.html.erb
<%= form_for(@micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
  <span class="picture">
    <%= f.file_field :picture, accept: 'image/jpeg,image/git.image/png' %>
  </span>
<% end %>

<script type="text/javascript">
  $('micropost_picture').bind('change', function() {
   var size_in_megabytes = this.files[0].size/1024/1024;
   if (size_in_megabytes > 5) {
    alert('Maximum file size is 5MB. Please choose a smaller file.'); 
   }
  });
</script>
```

しかし、このコードでは大きすぎるファイルのアップロードを完全には阻止できない。

このコードで仮に送信フォームを使った投稿をうまく制限できても、ブラウザのインスペクタ機能でJavaScriptをいじったり、curlなどを使って直接POSTリクエストを送信する場合には対応しきれない。

したがって、このコードに対して`micropost.rb`でバリデーションをかけることで大きすぎるファイルのアップロードを阻止できる。


####演習

1:5MB以上の画像ファイルを送信しようとするとどうなるか？

![スクリーンショット 2019-02-04 1.48.26.png](https://qiita-image-store.s3.amazonaws.com/0/244639/42c0aa6e-a8ad-b4e1-d512-00d9686643fb.png)

2:無効な拡張子のファイルを送信しようとするとどうなるか？

![スクリーンショット 2019-02-04 1.56.30.png](https://qiita-image-store.s3.amazonaws.com/0/244639/40fd022e-b078-6964-2ac1-c84941d75ec2.png)

###13.4.3 画像のリサイズ

ファイルサイズに対するバリデーションはうまくいったので、
画像サイズに対する制限を掛ける。

大きすぎる画像サイズがアプローどされるとレイアウトが壊れるので、
画像を表示させる前にサイズを変更するリサイズを行うようにする。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/f6fb6910-3015-a3da-9107-dbca956f8471.png)

出典：[図 13.21: 恐ろしく大きなアップロード画像](https://railstutorial.jp/chapters/user_microposts?version=5.1#cha-user_microposts)

画像をリサイズするために、`UnageMagick`というプログラムを開発環境にインストールする。

本番環境がHerokuであれば、既に本番環境でImageMagickが使えるようになっている。

クラウドIDEでは次のコマンドであればインストールできる。

```ruby
$ sudo yum install -y ImageMagick
```

次に`MiniMagick`という`ImageMagickとRubyをつなぐgem`を使って、画像をリサイズしてみる。

実際にリサイズする方法は様々あるが、今回は`resize_to_limit: [400, 400]`という方法を使う。

これは**縦横どちらかが400pxを超えていた場合、適切なサイズに縮小するオプション。**
(ちなみに小さすぎる画像を引き伸ばすこともできる)

```rb:picture_uploader.rb
class PictureUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  process resize_to_limit: [400, 400]
```

![スクリーンショット 2019-02-04 2.21.51.png](https://qiita-image-store.s3.amazonaws.com/0/244639/f0d616d7-695f-cc94-ef7c-69890bf4b8d4.png)

####演習

1:解像度の高い画像をアップロードし、リサイズされているかどうか確認してみる。
画像が長方形だった場合、リサイズはうまく行われているか？

![スクリーンショット 2019-02-04 2.27.48.png](https://qiita-image-store.s3.amazonaws.com/0/244639/638959ad-a4f3-f0ff-084a-5e37b954a480.png)

2:テストのエラーを取り除いてみる。

エラーがあるとのことだがエラーなし。

```ruby
57 tests, 300 assertions, 0 failures, 0 errors, 0 skips
```

とりあえず、指示通りテスト時はCarrierWaveに画像のリサイズをさせないようにしてみる。

```rb:skip_image_resizing.rb
if Rails.env.test?
  CarrierWave.configure do |config|
    config.enable_processing = false
  end
end
```

###13.4.4 本番環境での画像アップロード

先ほど実装した画像アップローダーは、開発環境で動かす分には問題ないが、
本番環境には適していない。

というのも、`picture_uploader.rb`にて`storage :file`という行によって、
**ローカルのファイルシステムに画像を保存するようになっているから**

本番環境では、ファイルシステムではなくクラウドストレージサービスに画像を保存するようにしてみる。

そのためには、`fog gem`を使うと簡単。

```rb:picture_uploader.rb
class PictureUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  process resize_to_limit: [400, 400]
  
  if Rails.env.production?
    storage :fog
  else
    storage :file
  end
  
  # storage :file
```

上記の条件式では`production?`という論理値を返すメソッドを使っている。

このメソッドを使うと、**環境毎に保存先を切り替えることができる。**


クラウドストレージサービスはSimple Storage Servide(S3)を使う。

セットアップ方法は以下。

1:AWSの「IAM」でユーザーを追加する。

![スクリーンショット 2019-02-04 3.58.48.png](https://qiita-image-store.s3.amazonaws.com/0/244639/c5aa2c19-cc79-dcce-35f6-2bb66ed64946.png)

2:グループの作成で、「AmazonS3FullAccess」のみ洗濯して作成。

![スクリーンショット 2019-02-04 3.59.41.png](https://qiita-image-store.s3.amazonaws.com/0/244639/546bd1be-bf49-f180-a98b-29b2587097b9.png)

3:任意のキーと値を入力してユーザーを作成する。
(CSVを保存しておく)

4:S3を開いてパケットを作成する

5:徹底で読み込み権限と書き込み権限を付与する。

設定を終えたら、`carrier_wave`ファイルを作成し、以下の設定を行う。

```rb:config/initializers/carrier_wave.rb
if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_credentials = {
      # Amazon S3用の設定
      :provider                     => 'AWS',
      :region                       => ENV['S3_REGION'],
      :aws_access_key_id            => ENV['S3_ACCESS_KEY'],
      :aws_secret_access_key        => ENV['S3_SECRET_KEY']
    }
    config.fog_directory            =  ENV['S3_BUCKET']
  end
end
```

あとは以下のコマンドでHerokuの環境変数を設定する。

```ruby
$ heroku config:set S3_ACCESS_KEY="ダウンロードしたAccessキー"
$ heroku config:set S3_SECRET_KEY="ダウンロードしたSecretキー"
$ heroku config:set S3_BUCKET_KEY="S3のBucketの名前"
$ heroku config:set S3_REGION="ap-northeast-1"
```

最後に、`.gitignore`ファイルを以下のように更新し、Gitに画像を保存するディレクトリを除かれるようにする。
(テスト用にアップした画像をGitに上げない)

```.gitignore
# アップロードされたテスト画像を無視する
/public/uploads
```

あとはいつも通り変更をトピックブランチにコミットし、masterブランチにマージする。

```ruby
$ rails t
$ git add -A
$ git commit -m "Add user microposts"
$ git checkout master
$ git merge user-microposts
$ git push
```

Herokuへのデプロイ後、DBのリセット、サンプルデータの生成を順に実行する。

```ruby
$ git push heroku
$ heroku pg:reset DATABSE
$ heroku run rails db:migrate
$ heroku run rails db:seed
```

これで本番環境で画像をアップロードできればOK.

が、しかし、アップするとエラーになる・・・。

試行錯誤の末、こちらの記事に到達。

[エラー<Message>Access Denied</Message> 〜Rails + Carrierwave + HerokuでAWS S3に画像を保存〜](https://qiita.com/yukiyukimiyaiwa/items/a9e0103c8342b81f6ac1)


Amazon S3の仕様が変わったため、以下のコードを追記する必要がある模様。

```rb:carrier_wave.rb
if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_provider = 'fog/aws' 
    config.fog_credentials = {
      # Amazon S3用の設定
      :provider              => 'AWS',
      :region                => ENV['S3_REGION'], 
      :aws_access_key_id     => ENV['S3_ACCESS_KEY'],
      :aws_secret_access_key => ENV['S3_SECRET_KEY']
    }
    config.fog_directory     =  ENV['S3_BUCKET']
    config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" } 
  end

  # 日本語ファイル名の設定
  CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/ 
end
```

また、S3のパケットポリシーに以下の記述を行う。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::[AWSIDを記入]:user/[IAMユーザー名を記入]"
            },
            "Action": "*",
            "Resource": "arn:aws:s3:::[パケット名を記入]/*"
        }
    ]
}
```

これで、再度`heroku config`の設定を行って、デプロイ。

画像がアップロードできればOK。

####演習

1:本番環境で解像度の高い画像をアップロードし、適切にリサイズされているか確認。
長方形の画像であっても、リサイズされているか？

![スクリーンショット 2019-02-04 7.23.52.png](https://qiita-image-store.s3.amazonaws.com/0/244639/311c3f00-6e95-9174-8f57-723cf9a0c5d7.png)

[第14章へ](https://qiita.com/yuuki_netb/items/07ba89a6d329bd2893e5)

#単語集

- references型

外部キーを追加する時に使う。

モデル生成時、引数に`〇〇:references`と渡すだけで一発で外部キーを追加できる。

- 複合インデックス

１つのデータの値に対してインデックスが二種類ある状態のこと。
複数の並び替え条件でインデックスを作る。

参考：[DBのインデックスと複合インデックス](https://qiita.com/towtow/items/4089dad004b7c25985e3)

- bulidメソッド

親モデルに対する子モデルのインスタンスを新たに生成したい場合に使うメソッド。
外部キーに値が入った状態でインスタンスを生成できる。

ただし、`new`メソッドと同様、DBに保存されない。　

- ラムダ式

Procやlambdaと呼ばれるオブジェクトを作成する文法。
->は、ブロックを引数に取り、Procオブジェクトを返す。

このオブジェクトは、`call`メソッドが呼ばれた時、ブロック内の処理を評価する。

使い方

```ruby
>> -> { puts "foo"}
=> #<Proc:0x00000003fc5a50@(irb):6 (lambda)>
>> -> { puts "foo" }.call
foo
=> nil
```

- dependent: :destroy

このオブションを`has_many`に渡すことで、関連づいた親モデルも一緒に削除されるようになる。

- time_ago_in_words

「何分前に投稿したか」という情報を文字列で出力するメソッド。

- any?

要素の中に１つでも真があればtrueを返す。１つもない場合はfalseを返す

- take

引数に指定した数だけを、オブジェクトに渡すメソッド。

- where

DBから、ある条件に当てはまるデータを全て取り出すメソッド。

- redirect_back(fallback_location: Your_page)

直前のページを開く時に使えるメソッド。キー値にパス名を入れると、そのページにリダイレクトできる。

- file_field

ファイル選択ボックスを表示する。

使い方

```ruby
file_field(オブジェクト名, プロパティ名[, オプション])
```

- picture?

画像用の属性名に応じて、CarrierWaveが自動的に生成してくれるメソッド。
micropostなどの属性名にこのメソッドを渡すことで使用できる。

- fixture_file_upload

fixtureで定義されたファイルをアップロードする特別なメソッド

- accept

サーバー側で受け入れ体制の整っているファイルを指定する属性。
この属性を指定することで、ファイル以外は送ることができない。

- initiailzers

インスタンスが生成された直後に実行されるメソッド。