Railsチュートリアル10章まとめ

#10.1 ユーザーを更新する

ユーザーを更新する行為は、新規ユーザーの作成に似ている。

|  |アクション  |リクエストに応答  |
|---|---|---|
|新規作成  |new  |POSTに対してcreate  |
|更新 |edit  |PATCHに対してupdate  |


##10.1.1編集フォーム
まずやるべきは、Usersコントローラーにeditアクションを追加し、それに対応するeditビューを実装。
ルーティングは`resources :users`のおかげで有効になっている。

Railsチュートリアル 表7.1を確認すると、ユーザー編集ページのURLは`/users/1/edit`となっている。
ここで、ユーザーidを取得するために用いるのが、`params[:id]`
paramとは、Railsで送られてきた値を取得するメソッド

```ruby:app/controllers/users_controller.rb
  def edit
    @user = User.find(params[:id])
  end
```
ユーザーのeditアクション

```:app/views/users/edit.html.erb
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @user, local: true) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Save changes", class: "btn btn-primary" %>
    <% end %>

    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="https://gravatar.com/emails" target="_blank">change</a>
    </div>
  </div>
</div>
```

ユーザーのeditビュー
ここでは、formの部分で、大部分がユーザー作成画面とかぶっているので、パーシャルでまとめるのが良い。

また、@userインスタンス変数を使って、idを取得し編集ページを表示している。

```ruby:HTML
<form accept-charset="UTF-8" action="/users/1" class="edit_user"
      id="edit_user_1" method="post">
  <input name="_method" type="hidden" value="patch" />
  .
  .
  .
</form>
```

WebブラウザではそのままではPATCHリクエストを送信できない。
そこで以下のコードで「偽装」している。

```ruby:
<input name="_method" type="hidden" value="patch" />
```

リスト 10.2のform_with(@user)のコードは、リスト 7.15のコードと完全に同じである。
ここでは、`Active Record`の`new_record`論理値メソッドでPOSTリクエストとPATCHリクエストを区別している。

```ruby:
$ rails console
>> User.new.new_record?
=> true
>> User.first.new_record?
=> false
```

true→POST
false→PATCH

最後に、ナビゲーションのリンクを実装

```ruby:
<%= link_to "Settings", edit_user_path(current_user) %>
```

`edit_user_path`もUsersリソースのおかげで使用可能。
current_userはヘルパーメソッド(９章で実装）

##10.1.2 編集の失敗
ゴールはupdateメソッドの実装。

```ruby:app/controllers/users_controller.rb
  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      # 更新に成功した場合を扱う。
    else
      render 'edit'
    end
  end
```
抑えておきたいのは、updateの呼び出しにuser_paramsを使っている点。
これは`Strong Parameters`というテクニック

user_paramsメソッドはx Usersコントローラー内部でのみ実行され、Web経由で外部ユーザーに晒される心配はなし。属性の許可を制限することで管理者権限を乗っ取られることを防ぐ。
(詳しくは7.3.2参照)

```ruby:
  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end
end
```

##10.1.3 編集失敗時のテスト
統合テストを行う

```:
$ rails generate integration_test users_edit
      invoke  test_unit
      create    test/integration/users_edit_test.rb
```
コマンドで統合テストを生成

まずは、編集失敗時のテストから。
流れとしては、編集ページにアクセス→editビューが描画されるか確認→無効な情報を送信→再度editビューが描画される

```ruby:test/integration/users_edit_test.rb

require 'test_helper'

class UsersEditTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end

  test "unsuccessful edit" do
    get edit_user_path(@user)
    assert_template 'users/edit'
    patch user_path(@user), params: { user: { name:  "",
                                              email: "foo@invalid",
                                              password:              "foo",
                                              password_confirmation: "bar" } }

    assert_template 'users/edit'
  end
end
```
ここでPATCHリクエストを送るために`patchメソッド`を使用している。
これは`get`,`post`メソッド等と同様に、HTTPリクエストを送るためのもの。
（HTTPリクエストとは、クライアント側からWebサーバーにリクエストする際送信するもの)