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で送られてきた値を取得するメソッド
def edit
@user = User.find(params[:id])
end
ユーザーのeditアクション
<% 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を取得し編集ページを表示している。
<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リクエストを送信できない。
そこで以下のコードで「偽装」している。
<input name="_method" type="hidden" value="patch" />
リスト 10.2のform_with(@user)のコードは、リスト 7.15のコードと完全に同じである。
ここでは、Active Record
のnew_record
論理値メソッドでPOSTリクエストとPATCHリクエストを区別している。
$ rails console
>> User.new.new_record?
=> true
>> User.first.new_record?
=> false
true→POST
false→PATCH
最後に、ナビゲーションのリンクを実装
<%= link_to "Settings", edit_user_path(current_user) %>
edit_user_path
もUsersリソースのおかげで使用可能。
current_userはヘルパーメソッド(9章で実装)
10.1.2 編集の失敗
ゴールはupdateメソッドの実装。
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参照)
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ビューが描画される
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サーバーにリクエストする際送信するもの)