railsチュートリアル第十三章 マイクロポストを削除する

###マイクロポストを削除する
マイクロポストリソースにポストを削除する機能を追加.
これはユーザー削除と同様に、"delete" リンクで実現します
今回は自分が投稿したマイクロポストに対してのみ削除リンクが動作するようにします。

####マイクロポストのパーシャルに削除リンクを追加する
app/views/microposts/_micropost.html.erb

```html
<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.
    <!--メソッド名の表すとおりですが、「3分前に投稿」といった文字列を出力します。-->
    <% if current_user?(micropost.user) %>
    <!--もし自分の投稿だったら-->
      <%= link_to "delete", micropost, method: :delete,
                                       data: { confirm: "You sure?" } %>
    <% end %>
  </span>
</li>
```

####Micropostsコントローラのdestroyアクション
app/controllers/microposts_controller.rb

```rb
class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]
  # create,destroyを行う前にログインを求めらえれる。
  before_action :correct_user,   only: :destroy

  def create
    @micropost = current_user.microposts.build(micropost_params)
    # 慣習的に関連するモデルを生成するときは、buildを使う
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
      # redirect_to は、view の表示には直接は関係なく、新たな HttpRequest が発行されます。
    else
      @feed_items = current_user.feed.paginate(page: params[:page])
      render 'static_pages/home'
      # action で view を指定しない場合、規約に従って、リソース名 や
      #   action名を元に、表示する view が決まります。
    end
  end

  def destroy
    @micropost.destroy
    flash[:success] = "Micropost deleted"
    redirect_to request.referrer || root_url
    # request.referrer 一つ前のURLを返します
    # || または
  end

  private

    def micropost_params
      params.require(:micropost).permit(:content)
      # マイクロポストのcontentカラムだけ取り出すことができる。
    end
    
    def correct_user
      @micropost = current_user.microposts.find_by(id: params[:id])
      # idをもとにユーザーのマイクロぽすとを探す
      redirect_to root_url if @micropost.nil?
      # マイクロポストが空であればホーム画面に行く
    end
end
```
###演習
1.
マイクロポストを作成し、その後、作成したマイクロポストを削除してみましょう。次に、Railsサーバーのログを見てみて、DELETE文の内容を確認してみてください。

確認

2.
redirect_to request.referrer || root_urlの行をredirect_back(fallback_location: root_url)と置き換えてもうまく動くことを、ブラウザを使って確認してみましょう（このメソッドはRails 5から新たに導入されました）。

確認
かっこなしでも動くらしい

###フィード画面のマイクロポストをテストする
Micropostsコントローラの認可をチェックする短いテストと、それらをまとめる統合テストを書くことです。

マイクロポスト用のfixtureに、別々のユーザーに紐付けられたマイクロポストを追加

####別のユーザーに所属しているマイクロポストを追加する
test/fixtures/microposts.yml

```yml
.
.
.
ants:
  content: "Oh, is that what you want? Because that's how you get ants!"
  created_at: <%= 2.years.ago %>
  user: archer

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

tone:
  content: "I'm sorry. Your words made sense, but your sarcastic tone did not."
  created_at: <%= 10.minutes.ago %>
  user: lana

van:
  content: "Dude, this van's, like, rolling probable cause."
  created_at: <%= 4.hours.ago %>
  user: lana
```

####間違ったユーザーによるマイクロポスト削除に対してテストする
test/controllers/microposts_controller_test.rb

```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
    # root_urlにリダイレクトされるか？
  end
end
```

####統合テスト
```
ubuntu:~/environment/sample_app (user-microposts) $ rails generate integration_test microposts_interface
Running via Spring preloader in process 9548
      invoke  test_unit
      create    test/integration/microposts_interface_test.rb
```

####マイクロポストのUIに対する統合テスト
test/integration/microposts_interface_test.rb

```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'
    # エラ〜メッセージが表示されているか？
    assert_select 'a[href=?]', '/?page=2'  
    # 正しいページネーションリンク
    # ページネートが２ページに行くか？
    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
    # root_urlにリダイレクトされているか？
    follow_redirect!
    # 後から調べる
    assert_match content, response.body
    # マイクロポストの数があれば、コンテントがあるか？
    # 投稿を削除する
    assert_select 'a', text: 'delete'
    # aタグにdeleteがあるか？
    first_micropost = @user.microposts.paginate(page: 1).first
    #１枚目の 1番目のマイクロポストを返す
    assert_difference 'Micropost.count', -1 do
    # 削除して一つ減っているか？
      delete micropost_path(first_micropost)
      # 先のマイクロポストを削除する
    end
    # 違うユーザーのプロフィールにアクセス（削除リンクがないことを確認）
    get user_path(users(:archer))
    # archerのuser_pathに行くことを要求
    assert_select 'a', text: 'delete', count: 0
    # aタグのdeleteが表示されていないか？
  end
end
```

####演習
1.
リスト 13.56で示した４つのコメント（「無効な送信」など）のそれぞれに対して、テストが正しく動いているか確認してみましょう。具体的には、対応するアプリケーション側のコードをコメントアウトし、テストが red になることを確認し、元に戻すと green になることを確認してみましょう。

飛ばす。

2.
サイドバーにあるマイクロポストの合計投稿数をテストしてみましょう。このとき、単数形（micropost）と複数形（microposts）が正しく表示されているかどうかもテストしてください。ヒント: リスト 13.58を参考にしてみてください。

```rb
.
.
.
require 'test_helper'

class MicropostsInterfaceTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end
.
.
.
  test "micropost sidebar count" do
    log_in_as(@user)
    # ログインさせる
    get root_path
    # ログインできたらホームページへの移動を要求
    assert_match "#{@user.microposts.count} microposts", response.body
    # ページの中に{@user.microposts.count}があるか？
    # まだマイクロポストを投稿していないユーザー
    other_user = users(:malory)
    # malory
    log_in_as(other_user)
    # maloryをログインさせる
    get root_path
    # root_path(ホーム画面)への要求
    assert_match "0 microposts", response.body
    # 0 micropostsがページのどこかにあるか？
    other_user.microposts.create!(content: "A micropost")
    # マイクロポストを作成する
    get root_path
    assert_match "1 micropost", response.body
    # 1 micropostがページのどこかに表示されているか？
  end
end
```