Rails初学者によるRailsチュートリアル学習記録⑨ 第7章

#目次
- [1. はじめに](#1-はじめに)
- [2. 第7章の概要](#2-第7章の概要)
- [3. 学習内容](#3-学習内容)
- [4. 終わりに](#4-終わりに)

#1. はじめに
- この記事は、Rails初学者の工業大学三年生がRailsチュートリアルの学習記録を<br>つけるための記事です。
- 筆者自体がRailsやWebについて知識が少ないので、内容の解釈などに<br>間違いがある可能性があります。(その時はコメントで指摘してくださると助かります！)
- Railsチュートリアル内ではRailsの内容以外にも、gitでのバージョン管理やHerokuを使ったデプロイも<br>学習しますが、gitに関しては既に私が学習済みのため学習記録には記述しません。
- 演習の記録も省略します。

#2. 第7章の概要
この章では、ユーザー登録機能を実装して、ブラウザからユーザー登録をできるようにしていきます。
RESTアーキテクチャに基づいたユーザーのページも使用できるようにして、より実際のwebアプリケーションに
近づいていく1章です。


1. ユーザー登録の準備
    1. RESTアーキテクチャによるルート
    1. デバッグ
    1. gravatarを使用する
1. ビューにフォームを作成する
    1. フォームの処理の流れ
    1. Strong Parameters
    1. フォーム送信後の処理
1. flashでウェルカムメッセージを表示する

#3. 学習内容
###1. ユーザー登録の準備
####1-1. RESTアーキテクチャによるルート
RESTアーキテクチャは、GET / POST / PATCH / DELETE の4つのHTTPメソッドに対応したアクションやリソースをデフォルトで提供します。
提供されるアクションの一覧を以下の表に示します。

| HTTPリクエスト | URL | アクション名 | 用途 |
|:-|:-|:-|:-|
| GET  | /users  | index  | ユーザー一覧を表示するページ  |
| GET  | /users/1  | show  | 特定のユーザーを表示するページ  |
| GET  | /users/new  | new  | ユーザーを新規作成するページ  |
| POST  | /users  | create  | ユーザーを作成するアクション  |
| GET  | /users/1/edit  | edit  | id=1 のユーザーを編集するページ  |
| PATCH  | /users/1  | update  | ユーザーを更新するアクション  |
| DELETE  | /users/1  | destroy  | ユーザーを削除するアクション  |

これらのアクションを使用するには<strong>routesファイル</strong>に`resources :users`という一行を追加する必要があります。
また上記の表の用途の列で、○○するページと○○するアクションという表記が混在していますが、
○○するページと表記されたアクションは、それに対応するビューを作成するのに対し、
○○するアクションと表記されたアクションはビューを必要とせず、処理を行った後に別のビューにリダイレクトします。

####1-2. デバッグ
この章で作成するプロフィルページはこのアプリケーション内での初めての動的なページです。
そのページではデータベースからユーザーのデータを取り出し、それを表示します。
ここでは、そのページが正しく動作しているかを確認できるようにしていきます。

デバッグ情報を表示させるには、ビューファイルに<strong>debugメソッド</strong>と<strong>params変数</strong>を使います。
この時、本番環境ではデバッグ情報を表示させたくないので、`if Rails.env.development?`を使うことで、
開発環境でのみデバッグ情報を表示させます。
以下のコードがデバッグ情報を挿入したビューファイルです。

```html:app/views/layoouts/application.html.erb
<!-- body部分のみを表示 -->
<body>
  <%= render 'layouts/header' %>
  <div class="container">
    <%= yield %>
    <%= render 'layouts/footer' %> 
    <%= debug(params) if Rails.env.development? %>  <!-- 開発環境でのみデバッグ情報を挿入する -->
  </div>
</body>
```

####1-3. gravatarを使用する
gravatarとは、メールアドレスと画像を紐づけることで、ユーザーのアイコンとしてその画像を表示できる機能です。
Railsでgravatarを使用するには、gravatar_forというヘルパーメソッドを使用します。
このヘルパーメソッドはUsersコントローラのヘルパーファイルに定義して以下のように使用します。

```ruby:app/helpers/users_helper.rb
module UsersHelper

# 引数で与えられたユーザーの Gravatar 画像を返す
  
def gravatar_for(user)
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
    image_tag(gravatar_url, alt: user.name, class: "gravatar")
  end
end
```

```html:app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<h1>
<%= gravatar_for @user %>  <!-- 第一引数にユーザーオブジェクトを渡す-->
<%= @user.name %>
</h1>
```
###2. フォームを作成する
####2-1. フォームの処理の流れ
Railsでフォームを実装するにはform_withヘルパーメソッドを使用する。
フォームを作るユーザー登録ページはUsersコントローラのnewアクションに対応させて、
newアクションで`@user = User.new`を実行することでオブジェクトを生成します。

以下のコードが登録フォームのコードです。

```ruby:app/views/users/new.html.erb
# フォーム部分のみを抜粋
<%= form_with(model: @user, local: true) do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>

  <%= f.label :email %>
  <%= f.email_field :email %>

  <%= f.label :password %>
  <%= f.password_field :password %>

  <%= f.label :password_confirmation, "Confirmation" %>
  <%= f.password_field :password_confirmation %>

  <%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
```
上のコードのようにlabelと入力部分(input)をペアで作成し、
ペアは引数のシンボルで判断されます。
このシンボルはフォームに入力されたデータを扱うときにも使用します。

ボタンを押すとform_withの引数になっている@userが新しいユーザーであるとRailsが判断して、
POSTリクエストを/users、つまりcreateアクションに入力された値を送信します。
上記の処理の流れは
`<%= form_with(model: @user, local: true) do |f| %>`というRubyのコードが
`<form action="/users" class="new_user" id="new_user" method="post">`というHTMLを生成していることを意味します。

入力された値はcreateアクションにparamsハッシュとして渡されます。
paramsハッシュには各リクエストの情報が含まれていますがユーザー登録の場合は、
userハッシュが格納されています。つまり、ハッシュが入れ子になっている状態です。
そして、userハッシュの中にフォームに入力された値がフォームのシンボルとともに格納されています。
よって、createアクションで`@user = User.new(params[:user])`と書くことで、
フォームに入力された値を持ったユーザーが作成できます。

上記の@userにsaveメソッドを用いればユーザー登録ができるようになります。
しかし、上記のparamsを渡す方法ではユーザーが送信したデータをそのままUserオブジェクトに渡しており、
この方法はセキュリティ上の欠陥があります。

具体的な例としては、Userモデルにadmin属性という属性があり、サイトの管理者はその属性の値が1になるという運用をした場合、
admin='1'という値をprams[:user]に紛れ込ませて渡すことで、誰でもサイトの管理者権限を得ることができてしまいます。
このような欠陥を次節のStrongParametersで解消します。

####2-2. Strong Parameters
Strong Parametersはparamsハッシュで必須の値や許可された値を決めることができます。
よって、許可されていない値を受け取らないことで、先述した例のような欠陥を解消できます。

この機能を実装するにはuser_paramsというメソッドを使用するのが慣習です。
このメソッドはUsersコントローラに書き、外部ユーザーから隠すために<strong>privateキーワード</strong>を使用します。

```ruby:app/views/users/new.html.erb
# user_paramsメソッドの部分のみを抜粋
private
  def user_params
    params.require(:user).permit(:name, :email, :password, :password_confirmation)
  end 
<% end %>
```
そして、createアクションでのオブジェクト生成にこのメソッドを使用します。
`@user = User.new(user_params)`このように記述して、paramsハッシュを安全に扱っています。

####2-3. フォーム送信後の処理
######① 登録に成功したときの処理
ユーザー登録に成功した場合は、自分自身のプロフィールページにリダイレクトし、
そこでウェルカムメッセージを表示させます。

まず、リダイレクトは<strong>redirect_toメソッド</strong>で実装します。
@user.saveが成功したときに`redirect_to @user`というコードを実行すると、
railsが自動で判断してuser_url(@user)というプロフィールページにリダイレクトするコードに変換します。

ウェルカムメッセージはflashという特殊な変数で実装します。
登録に成功したときに、`flash[:success] = "Welcome to the Sample App!"`と書くことで、
flash変数にメッセージを代入します。
:successというキーを使用しているのはRailsの慣習で、成功時のメッセージを意味します。

メッセージが代入されたflash変数を、ビューで使用することでウェルカムメッセージを表示します。

```ruby:app/views/layouts/application.html.erb
<div class="container">
  <% flash.each do |message_type, message| %>
    <div class="alert alert-<%= message_type %>"><%= message %></div>
  <% end %>
  <%= yield %>
  <%= render 'layouts/footer' %>
  <%= debug(params) if Rails.env.development? %>
</div>
```
flashの機能とは直接関係ないのですが、`<div class="alert alert-<%= message_type %>"><%= message %></div>`
この行でのclassの設定にRubyが用いられています。
現状ではウェルカムメッセージしかflashで扱っていませんが、他のメッセージも使うことになった場合に
メッセージの種類に合わせてcssを切り替えることができるようになります。

######② 登録に失敗したときの処理
ユーザー登録に失敗した場合は、エラーメッセージを表示してユーザー登録に失敗したことを
ユーザーに分かりやすく伝える必要があります。

Railsはエラーの発生時に表示させたいメッセージを自動で生成してくれています。
それはuser.errors.full_messageというオブジェクトに配列として格納されています。
それをビューに表示できるようなパーシャルを作成しましょう

```ruby:app/views/layouts/application.html.erb
# エラーがあるときのみパーシャルを表示
<div class="container">
  <% flash.each do |message_type, message| %>
    <div class="alert alert-<%= message_type %>"><%= message %></div>
  <% end %>
  <%= yield %>
  <%= render 'layouts/footer' %>
  <%= debug(params) if Rails.env.development? %>
</div>
```


#4. 終わりに
この章で実際のアプリケーションのようにブラウザからユーザー登録ができるようになったので、
Herokuに上げて開発環境でなく本番環境でアプリケーションを動かすことができました。

実装したユーザー登録ではユーザー自身の情報を扱うということもあり、Railsチュートリアルでも
セキュリティに関する内容が増えてきました。
この記事では書いていませんが、本番環境でSSLを使用したり本番環境用のWebサーバーを使用したりなども行っています。
セキュリティに関する知識は資格試験の勉強などで勉強しましたが、実際に扱うことは初めてなのでセキュリティの内容は
注意深く実践していきたいです。