Railsチュートリアル 第7章 ユーザー登録 - ユーザーを表示する

静的なページ、コントローラ、モデルと来て、ここからはいよいよ真に動的なページの作成に取り掛かっていきます。その記念すべき第一弾となるのが、今回実装するプロフィールページです。

今節においては、以下の要素が表示できるプロフィールページを作成していきます。

* ユーザーの名前
* プロフィール写真

プロフィールページの最終的な完成像としては、以下の要素が表示できることを目指します。

* プロフィール写真
* 基本ユーザーデータ
* マイクロポストの一覧

# デバッグとRails環境

## Webサイトのレイアウトにデバッグ情報を追加する

デバッグ情報の追加は、サンプルアプリケーションに動的なページを追加する前段階となります。使用するのは以下のリソースです。

* `debug`メソッド
* `params`変数

```diff:app/views/layouts/application.html.erb
  <!DOCTYPE html>
  <html>
    ...略
    <body>
      <%= render 'layouts/header' %>
      <div class="container">
        <%= yield %>
        <%= render 'layouts/footer' %>
+       <%= debug(params) if Rails.env.development? %>
      </div>
    </body>
  </html>
```

以上のコードを追加することにより、開発環境(development)において、各プロフィールページにデバッグ用の情報が表示されるようになります。

特筆すべきは以下のRubyコードです。

```ruby:
if Rails.env.development?
```

これは、開発環境(development)でのみ`true`になる条件式です。

```erb:
<%= debug(params) if Rails.env.development? %>
```

ゆえに、上記の埋め込みRubyは以下の動作をすることになります。

* 本番環境やテストには挿入されない
* 開発環境[^テスト環境はどうなのか]でのみ、各プロフィールページにデバッグ用の情報を表示する

[^テスト環境はどうなのか]: テスト環境でデバッグ情報が表示されても、「ユーザーに見えてはならない情報が見えてしまう」等の問題に直接つながるわけではありません。しかしながら、「デバッグ情報が開発環境以外で表示されるのは望ましくない」というのもまた事実です。

## デバッグ出力の表示を整形するために、カスタムスタイルシートに追加の記述を行う

```diff:app/assets/stylesheets/custom.scss
    @import "bootstrap-sprockets";
    @import "bootstrap";

    /* mixins, variables, etc. */

    $gray-medium-light: #eaeaea;

+   @mixin box_sizing {
+       -moz-box-sizing: border-box;
+       -webkit-box-sizing: border-box;
+       box-sizing: border-box;
+   }

    ..略
+
+   /* miscellaneous */
+   .debug_dump {
+       clear: both;
+       float: left;
+       width: 100%;
+       margin-top: 45px;
+       @include box_sizing;
+   }
```

上記は、デバッグ出力をきれいに整形するために`app/assets/stylesheets/custom.scss`に追加で記述するコードです。「Sassのミックスイン機能を使用している(`@mixin box_sizing`以下の記述)」というのがポイントです。

結果として、デバッグ環境のHomeページをWebブラウザでレンダリングした結果は、現在のところは以下のスクリーンショットのような出力となります。

<img width="1156" alt="スクリーンショット 2019-10-13 22.41.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/8db4482f-39a3-b5d9-63c5-b9306133167f.png">

### Sassのミックスイン機能

Sassのミックスイン機能を使うことにより、CSSルールのグループをパッケージ化して複数の要素に適用することができます。

例えば、例1のコードは例2のように展開されます。

```sass:例1
@mixin box_sizing {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

.debug_dump {
    /* ...略 */
    @include box_sizing;
}
```

```sass:例2
.debug_dump {
    /* ...略 */
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}
```

## デバッグ出力の内容

# 演習 - デバッグとRails環境

## 1. ブラウザから/aboutにアクセスし、デバッグ情報が表示されていることを確認してください。このページを表示するとき、どのコントローラとアクションが使われていたでしょうか?`params`の内容から確認してみましょう。

`params`の内容は以下のとおりです。

```
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  controller: static_pages
  action: about
permitted: false
```

* コントローラは`static_pages`
* アクションは`about`

以上であることがわかります。

## 2. Railsコンソールを開き、データベースから最初のユーザー情報を取得し、変数`user`に格納してください。その後`puts user.attributes.to_yaml`を実行すると何が表示されますか?

```
>> user = User.find(1)
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2019-10-13 06:43:53", updated_at: "2019-10-13 06:43:53", password_digest: "$2a$10$rb26ZPyWkUh8T/cWML/OM.VhDiuJaii877zf3SvsfN5...">

>> puts user.attributes.to_yaml
---
id: 1
name: Michael Hartl
email: mhartl@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &1 2019-10-13 06:43:53.935111000 Z
  zone: &2 !ruby/object:ActiveSupport::TimeZone
    name: Etc/UTC
  time: *1
updated_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &3 2019-10-13 06:43:53.935111000 Z
  zone: *2
  time: *3
password_digest: "$2a$10$rb26ZPyWkUh8T/cWML/OM.VhDiuJaii877zf3SvsfN56IOU/ibHei"
=> nil
```

## 2.2. 2.1.で表示された結果と、`y`メソッドを使った`y user.attributes`の実行結果を比較してみましょう。 

```
>> y user.attributes
---
id: 1
name: Michael Hartl
email: mhartl@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &1 2019-10-13 06:43:53.935111000 Z
  zone: &2 !ruby/object:ActiveSupport::TimeZone
    name: Etc/UTC
  time: *1
updated_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &3 2019-10-13 06:43:53.935111000 Z
  zone: *2
  time: *3
password_digest: "$2a$10$rb26ZPyWkUh8T/cWML/OM.VhDiuJaii877zf3SvsfN56IOU/ibHei"
=> nil
```

`puts user.attributes.to_yaml`の結果と`y user.attributes`の結果は、特に変わりないように見えます。いずれも戻り値は`nil`であり、副作用として、ユーザーオブジェクトの内容をyamlとしてパースしたものが標準出力に出力されています。

# Usersリソース

## RDB上に一人分のユーザー情報が登録されていることを確認する

ユーザープロフィールページを作成するには、RDB上にユーザーが登録されている必要があります。第6章の時点で「Railsコンソールを使ってRDB上にユーザーを登録する」という操作を行ったのは、実はそのためだったのです。

```
# rails console

>> User.count
   (2.1ms)  SELECT COUNT(*) FROM "users"
=> 1
>> User.first
  User Load (0.4ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "mhartl@example.com", created_at: "2019-10-13 06:43:53", updated_at: "2019-10-13 06:43:53", password_digest: "$2a$10$rb26ZPyWkUh8T/cWML/OM.VhDiuJaii877zf3SvsfN5...">
```

ここでは、「RDB上に既に1個のユーザー情報が存在しており、そのユーザーのIDは1である」というのがポイントです。

## RESTアーキテクチャと、ユーザー情報の表示の実装計画

Railsアプリケーションにおいては、RESTアーキテクチャの習慣に従い、「データの作成・表示・更新・削除[^CRUD]をリソースに割り付ける」という手法を取ることが好まれます。HTTP標準のリクエストとCRUDの各操作は、以下のように対応付けられるのが一般的です。

|HTTP標準のリクエスト|CRUDの各操作|
|------|------|
|POST |Create |
|GET |Read |
|PATCH |Update |
|DELETE |Delete |

RESTの原則に従う場合、リソースへの参照は、リソース名とユニークなIDを使うのが一般的です。例えば、id=1のユーザーの情報を表示する場合、対応する操作は、「/users/1というURLに対してGETリクエストを発行する」という操作になります。

というわけで、RESTの原則に従うならば、ユーザー情報に対するCRUD機能のコントローラを実装するためには、POST・GET・PATCH・DELETEの各リクエストをコントローラのアクションに割り付けていくというのが基本方針となります。

[^CRUD]: データの作成・表示・更新・削除は、総称して「CRUD」と呼ばれます。「Create, Read, Update, Delete」の略です。

### `show`アクション、その他RESTfulなUsersリソースに対するルーティングが利用できるようにする

Railsのコントローラで定義されたアクションは7つあり、そのうちの`show`アクションは、暗黙的にGETリクエストと対応付けられています。RailsのREST機能が有効になっていれば、GETリクエストは自動的に`show`アクションとして扱われるのです。

ただ、現時点で/users/1にアクセスするとエラーになります。/users/1へのGETリクエストに対するルーティングが定義されていないためです。

```
Started GET "/users/1" for 172.17.0.1 at 2019-10-13 15:37:30 +0000
Cannot render console from 172.17.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
  
ActionController::RoutingError (No route matches [GET] "/users/1"):
...略
```

というわけで、/users/1へのGETリクエストに対するルーティングを定義しましょう。修正するファイルは、`/config/routes.rb`です。

```diff:/config/routes.rb
  Rails.application.routes.draw do
    get 'users/new'

    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'
+   resources :users
  end
```

`/config/routes.rb`に`resources :users`という記述を加えると、/users/1に限らず、RESTfulなUsersリソースで必要となるHTTPリクエスト(POST・GET・PATCH・DELETE)と対応するURLの組すべてに対するルーティングが定義されます。実際に定義されるルーティングの一覧表は、[Railsチュートリアルの表 7.1](https://railstutorial.jp/chapters/sign_up?version=5.1#table-RESTful_users)の通りになります。

## 次になすべきことは

ただ、ルーティングが定義されたとしても、まだルーティング先のアクションがコントローラで定義されていないですし、ルーティング先のページが存在するわけでもありません。/users/1にアクセスすると、やはりエラーになります。

```
Started GET "/users/1" for 172.17.0.1 at 2019-10-13 15:50:14 +0000
Cannot render console from 172.17.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
  
AbstractController::ActionNotFound (The action 'show' could not be found for UsersController):
...略
```

エラーにはなりますが、その内容が変化していますね。「ルーティングが見つからない」というのではなく、「コントローラで`show`アクションが定義されていない」という内容になりました。

この状態から`show`アクションが正しく動作するようにするためには、以下の2つの実装が必要になります。

* Usersリソースに対するshowビューの実装
* Usersコントローラに対する`show`アクションの実装

## Usersリソースに対するshowビューの実装

Railsにおいて、「Usersリソースに対するshowビュー」を指すファイルは、`app/views/users/show.html.erb`となります。しかしながら、現時点で当該ファイルは存在しません。まずは`app/views/users/show.html.erb`を新規作成するのが最初のプロセスとなります。

`app/views/users/show.html.erb`の最初の内容は、以下の通りです。「埋め込みRubyにより、ユーザー名とメールアドレスを表示する」という内容になります。

```ruby:`app/views/users/show.html.erb`
<%= @user.name %>, <%= @user.email %>
```

## Usersコントローラに対する`show`アクションの実装

Usersリソースに対するshowビューが正常に動作するためには、Usersコントローラに`show`アクションに、対応する`@user`変数が実装されている必要があります。編集するファイルは`app/controllers/users_controller.rb`です。以下の内容を追加します。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController
+
+   def show
+     @user = User.find(params[:id])
+   end
+
    def new
    end
  end
```

ポイントは以下です。

* ユーザーのid読み出しには、`params`メソッドを用いている
    * Usersコントローラが正常なリクエストを受け取ると、例えばid=1の場合、`@user = User.find(1)`という処理を実行することに成る
* `param[:id]`の戻り値は文字列型の`"1"`だが、`find`メソッドでは自動的に整数型に変換される

ここまでの変更を反映した時点で、/users/1が完全に動作するようになります。以下にスクリーンショットを掲載します。

<img width="1156" alt="スクリーンショット 2019-10-14 20.59.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/a2f04ae2-808e-8c02-ee7b-f548fcfea1b5.png">

```デバッグ情報
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  controller: users
  action: show
  id: '1'
```

上記のとおり、デバッグ情報から`param[:id]`の値を確認できるようになりました。`id: '1'`というのは、/users/`:id`というURLから取得された値です。これにより、`User.find(params[:id])`が`User.find(1)`と解釈される一連の仕組みが確立されました。

# 演習 - Usersリソース

## 1. 埋め込みRubyを使って、マジックカラム (created_atとupdated_at) の値をshowページに表示してみましょう ([リスト 7.4](https://railstutorial.jp/chapters/sign_up?version=5.1#code-stub_user_view))。

変更対象のファイルは`app/views/users/show.html.erb`です。以下のように変更してみます。

```diff:app/views/users/show.html.erb
  <%= @user.name %>, <%= @user.email %>
+ Created: <%= @user.created_at %>, Updated: <%= @user.updated_at %>
```

結果は以下のようになりました。

<img width="1156" alt="スクリーンショット 2019-10-14 21.11.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/97e793de-ab30-24a8-5717-8f34e34a354b.png">


## 2. 埋め込みRubyを使って、`Time.now`の結果をshowページに表示してみましょう。ページを更新すると、その結果はどう変わっていますか? 確認してみてください。

```diff:app/views/users/show.html.erb
  <%= @user.name %>, <%= @user.email %>
  Created: <%= @user.created_at %>, Updated: <%= @user.updated_at %>
+ 現在の時刻: <%= Time.now %>
```

<img width="1156" alt="スクリーンショット 2019-10-14 22.12.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/8c2cf17e-d5a5-cacb-ae5d-c88b59b4471c.png">

<img width="1156" alt="スクリーンショット 2019-10-14 22.12.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/7e056d62-3f67-f80d-737c-57495f6ca1c5.png">

「現在の時刻:」以降の表示内容が、Webページを更新するたびに変わっていきます。

# debuggerメソッド

## byebug gemは既にインストールされている

最初の環境構築の段階で、開発環境(Development)向けに`byebug`というGemをセットアップしました。

```:Gemfile
source 'https://rubygems.org'
...略

group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug',  '9.0.6', platform: :mri
end

...略
```

この`byebug` gemが提供する`debugger`メソッドにより、今まで用いてきた`debug`メソッドよりさらに直接的にデバッグを行うことが可能です。

## 実際にdebuggerメソッドを使ってみる

まずは、実際に`debugger`メソッドをRailsアプリケーションに差し込んでみましょう。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController

    def show
      @user = User.find(params[:id])
+     debugger
    end

    def new
    end
  end
```

この状態で/users/1というページを表示すると、`rails server`を立ち上げたシェルに、以下のようなプロンプトが出てきます。

```
(byebug)
```

このプロンプトでは、Railsコンソールのようにコマンドを実行することができ、アプリケーションの`debugger`が呼び出された瞬間の状態を確認することが可能です。

```
(byebug) @user.name
"Michael Hartl"
(byebug) @user.email
"mhartl@example.com"
(byebug) params[:id]
"1"
```

プロンプトを抜けるには、Ctrl-Dを押します。また、デバッグが終わったら`debugger`行は削除する必要があります。プロンプトが出ている状態だと、アプリケーションの実行が中断されるからです。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController

    def show
      @user = User.find(params[:id])
-     debugger
    end

    def new
    end
  end
```

## debuggerメソッドを使う際のポイント

* Railsアプリケーション内でよくわからない挙動があったら、躊躇なく`debugger`コードを挿し込んで調べてみる
* `debugger`コードは、トラブルが起こっていそうなコードのできるだけ近くに差し込む

byebug gemによるシステム状態の調査は、アプリケーションの動作の追跡・デバッグに際して非常に強力なツールとなります。

# 演習 - debuggerメソッド

## 1. showアクションの中にdebuggerを差し込み (リスト 7.6)、ブラウザから /users/1 にアクセスしてみましょう。その後コンソールに移り、putsメソッドを使ってparamsハッシュの中身をYAML形式で表示してみましょう。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController

    def show
      @user = User.find(params[:id])
+     debugger
    end

    def new
    end
  end
```

```
(byebug) puts params.to_yaml
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  controller: users
  action: show
  id: '1'
permitted: false
nil
```

## 2. `new`アクションの中に`debugger`を差し込み、/users/new にアクセスしてみましょう。`@user`の内容はどのようになっているでしょうか? 確認してみてください。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController

    def show
      @user = User.find(params[:id])
    end

    def new
+     debugger
    end
  end
```

以下の通り、`@user`を`puts`しても、型もアドレスも表示されません。

```
(byebug) puts @user

nil
```

一方で、`show`アクションに`debugger`メソッドを挿入した状態で`@user`を`puts`した結果は以下のようになります。型とアドレスが表示されていますね。

```
(byebug) puts @user
#<User:0x00007f34780e2de8>
nil
```

# Gravater画像とサイドバー

## Gravatarとは

Globally Recognized AVATARの略です。プロフィール写真をアップロードして、指定のメールアドレスと紐付ける事ができるサービスです。Gravatarを利用することにより、プロフィール写真の運用について、以下の利便を実現することができます。

* プロフィール写真をアップロードする面倒な作業から解放される
* 写真が欠けるトラブルから解放される
* 画像の置き場所の悩みが解決される

Gravatar画像を利用できるサービスとしては、例えば以下のものが挙げられます。

* Github
* Slack
* Qiita

RailsアプリケーションでもGravatarのプロフィール画像を利用することができます。

## `gravatar_for`ヘルパーメソッドを呼び出すようにする

現在作成中のアプリケーションでは、「`gravatar_for`というヘルパーメソッドを使ってGravatarの画像を利用できるようにする」とう方針を取ることとします。

まず、ユーザー表示ビューで`gravatar_for`ヘルパーメソッドを使用するようにコードを書き換えていきましょう。

```diff:app/views/users/show.html.erb
- <%= @user.name %>, <%= @user.email %>
+ <% provide(:title, @user.name) %>
+ <h1>
+   <%= gravatar_for @user %>
+   <%= @user.name %>
+ </h1>
```

「デフォルトでは、ヘルパーファイルで定義されているメソッドは、自動的にすべてのビューで利用できる」という言及は注目に値します。

なお、今回は、利便性を考え「`gravatar_for`をUsersコントローラに関連付けられているヘルパーファイルに置く」という方針を取ります。

## 文字列に対するMD5ハッシュを得る

GravatarのURLは、ユーザーのメールアドレスをMD5というハッシュ関数でハッシュ化したものを用いています。そのため、Gravatarを利用するシステムの側でもMD5ハッシュを得る処理を実装する必要があります。

Rubyでは、`Digest`ライブラリの`hexdigest`メソッドを用いることにより、文字列に対するMD5ハッシュを得ることができます。以下のRailsコンソールの処理結果がその例です。

```
>> email = "MHARTL@example.COM"
=> "MHARTL@example.COM"
>> Digest::MD5::hexdigest(email.downcase)
=> "1fda4469bcbec3badf5418269ffc5968"
```

以下の事柄は重要です。

* RubyのStringクラスの`downcase`メソッドを用いて、`hexdigest`の引数を小文字に変換している
    * 現在作成中のアプリケーションではメールアドレスの大文字小文字を区別しない一方、MD5ハッシュを生成するための入力では大文字小文字を区別するため
* 現在作成中のアプリケーションを前提とした場合、実際のところ、MD5ハッシュを生成する時点でメールアドレスを小文字に変換する処理を入れるのは冗長である
    * 現在作成中のアプリケーションでは、[ユーザー情報を新規に作成してRDBMSに保存する時点でメールアドレスを小文字に変換する処理を行っている](https://qiita.com/rapidliner00/items/16a18013da57579b5345#%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%AF%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AE%E5%AE%9F%E8%A3%85)ため
* `gravatar_for`メソッドが単独で呼び出される可能性を考え、MD5ハッシュを生成する時点で小文字に変換する処理を入れている

## `gravatar_for`ヘルパーメソッドを定義する

MD5ハッシュを得る処理の内容がわかったので、実際に「Railsアプリケーションの登録メールアドレスを元に、Gravatarからプロフィール画像を得る」という処理を実装していきましょう。

```app/helpers/users_helper.rb
  module UsersHelper
+   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
```

`image_tag`メソッドのオプションハッシュには、`alt`属性と`class`属性を与えています。それぞれ以下の意味になります。

* `alt`属性の内容は、画像が表示できない場合の代替テキストを意味する
* `class`属性の内容により、HTMLの各要素をグループ化し、主にCSSで使うことができる

## 上記のコードを追加しても、プロフィール画像が表示されない場合

<img width="1156" alt="スクリーンショット 2019-10-16 7.13.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/9b1e4ecf-10eb-eb5c-36eb-35ce1bc4bc29.png">

ここまでのコードを追加して、改めて/users/1をブラウザで表示した結果です。…プロフィール画像が表示されていません。なぜでしょうか。

[teratailに答えがありました。](https://teratail.com/questions/134967)当方の環境でも、確かに`img`要素に対して`display: none`という内容のCSSコードが存在します（下掲スクリーンショット）。

<img width="1089" alt="スクリーンショット 2019-10-16 7.16.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/3172e313-2d5e-eac4-d63e-2092e821d3a5.png">

原因は何かというと、第5章の演習で追加したコード（[リスト 5.11](https://railstutorial.jp/chapters/filling_in_the_layout?version=5.1#code-css_hide_image)）のようです。`app/assets/stylesheets/custom.scss`の対応する部分のコードを削除します。

```diff:app/assets/stylesheets/custom.scss
    @import "bootstrap-sprockets";
    @import "bootstrap";

  ...略
-
-   img {
-       display: none;
-   }

  ...略
```

<img width="1160" alt="スクリーンショット 2019-10-16 7.44.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/43259c11-673a-755d-c1e6-3c89d6a5a580.png">

今度こそプロフィール画像が表示されるようになりました。

## 実際にGravatarに登録されている情報を使ってみる

example@railstutorial.orgというメールアドレスに対しては、実際にGravatarにプロフィール画像が登録されています。当該メールアドレスを使って、実際にGravatarに登録されている情報を参照してみましょう。

現時点でユーザーの登録情報を変更するフォームは実装していないので、ユーザーの登録情報の変更は`rails console`から行っていきます。

```
# rails console

>> user = User.first
...略
>> user.update_attributes(name: "Example User",
?> email: "example@railstutorial.org",
?> password: "foobar",
?> password_confirmation: "foobar")
．．．略
=> true

>> exit
```

<img width="1160" alt="スクリーンショット 2019-10-16 7.54.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/edade6da-3b93-ed1a-0611-154dff6c95b0.png">

Gravatarに登録されているプロフィール画像が表示されています。

## サイドバーの最初のバージョン

### ユーザーの`show`ビューにサイドバーを追加する

ユーザーの`show`ビューにサイドバーを追加していきましょう。まずは以下のように、`app/views/users/show.html.erb`を全面的に書き換えていきます。

```erb:app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <h1>
        <%= gravatar_for @user %>
        <%= @user.name %>
      </h1>
    </section>
  </aside>
</div>
```

ポイントは以下です。

* サイドバーは、HTML5の`aside`要素を使って実装している
* HTML全体として、以下のクラスを使っている
    * `row`
    * `col-md-4`

`row`クラスと`col-md-4`クラスは、いずれもBootstrapフレームワークで使われているクラスの名前です。

### SCSSを使ってサイドバーなどのユーザー表示ページにスタイルを与える

サイドバーの構成・クラス名が決まると、SCSSでスタイルを与えることができるようになります。今回は、以下のようなスタイルを与えていきます。

```diff:app/assets/stylesheets/custom.scss
    ...略
+
+ /* sidebar */
+
+ aside {
+     section.user_info {
+         margin-top: 20px;
+     }
+     section {
+         padding: 10px 0;
+         margin-top: 20px;
+         &:first-child {
+             border: 0;
+             padding-top: 0;
+         }
+         span {
+             display: block;
+             margin-bottom: 3px;
+             line-height: 1;
+         }
+         h1 {
+             font-size: 1.4em;
+             text-align: left;
+             letter-spacing: -1px;
+             margin-bottom: 3px;
+             margin-top: 0px;
+         }
+     }
+ }
+
+ .gravatar {
+     float: left;
+     margin-right: 10px;
+ }
+
+ .gravatar_edit {
+     margin-top: 15px;
+ }
    ...略
```

ここまでコードを追加した時点において、/users/1をブラウザで表示した結果です。

<img width="1160" alt="スクリーンショット 2019-10-16 12.34.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/b1659a08-763d-a5e0-59d3-f882f5099e26.png">

# 演習 - Gravater画像とサイドバー

## 1. (任意) Gravatar上にアカウントを作成し、あなたのメールアドレスと適当な画像を紐付けてみてください。メールアドレスをMD5ハッシュ化して、紐付けた画像がちゃんと表示されるかどうか試してみましょう。

メールアドレスをMD5ハッシュ化する手順は、Railsコンソールで試してみます。「文字列を引数として与えてMD5ハッシュを生成する」というメソッドは、Rubyの`Digest::MD5::hexdigest`でしたね。

```
# rails console --sandbox

>> Digest::MD5::hexdigest([Qiitaの登録メールアドレス])
=> "0aad88c4503ba3e1308c13025b89d4e5"
```

Qiitaの登録メールアドレスのMD5ハッシュが得られました。というわけで、Webブラウザで https://secure.gravatar.com/avatar/0aad88c4503ba3e1308c13025b89d4e5 にアクセスしてみます。きちんとQiitaのプロフィール画像が表示されています。

## 2. [7.1.4](https://railstutorial.jp/chapters/sign_up?version=5.1#sec-a_gravatar_image)で定義した`gravatar_for`ヘルパーを[リスト 7.12](https://railstutorial.jp/chapters/sign_up?version=5.1#code-gravatar_option)のように変更して、`size`をオプション引数として受け取れるようにしてみましょう。

> うまく変更できると、`gravatar_for user, size: 50`といった呼び出し方ができるようになります。

```diff:app/helpers/users_helper.rb
  module UsersHelper
-   def gravatar_for(user)
+   def gravatar_for(user, options = { size:80 })
      gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
+     size = options[:size]
-     gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
+     gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
      image_tag(gravatar_url, alt: user.name, class: "gravatar")
    end
  end
```

`app/views/users/show.html.erb`において、`gravatar_for`メソッドに`size`属性を与えず、メールアドレスがexample@railstutorial.orgである場合、Gravatarのプロフィール画像のURLが`https://secure.gravatar.com/avatar/bebfcf57d6d8277d806a9ef3385c078d?s=80`となります。

`app/views/users/show.html.erb`の内容に以下の変更を加えたらどうなるでしょう。`gravatar_for`メソッドの`size`属性に`50`という値を与えたものです。

```diff:app/views/users/show.html.erb
  <% provide(:title, @user.name) %>
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <h1>
-         <%= gravatar_for @user %>
+         <%= gravatar_for @user, size: 50 %>
          <%= @user.name %>
        </h1>
      </section>
    </aside>
  </div>
```

スクリーンショットは以下のようになりました。Gravatarのプロフィール画像のURLは`https://secure.gravatar.com/avatar/bebfcf57d6d8277d806a9ef3385c078d?s=50`となっています。

<img width="1160" alt="スクリーンショット 2019-10-16 18.26.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/e1f38de6-6b28-f421-b017-881d87b12ab0.png">


## 3. 先ほど変更した[リスト 7.12](https://railstutorial.jp/chapters/sign_up?version=5.1#code-gravatar_option)を、[リスト 7.13](https://railstutorial.jp/chapters/sign_up?version=5.1#code-gravatar_keyword)のように置き換えてもうまく動くことを確認してみましょう。この２つの実装方法はどういった違いがあるのでしょうか? 考えてみてください。

以下はオプションハッシュを使ったコードに対するキーワード引数を使ったコードの差分です。

```diff:app/helpers/users_helper.rb
  module UsersHelper
-   def gravatar_for(user, options = { size:80 })
+   def gravatar_for(user, size: 80)
      gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
-     size = options[:size]
      gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}?s=#{size}"
      image_tag(gravatar_url, alt: user.name, class: "gravatar")
    end
  end
```

`app/views/users/show.html.erb`において、`gravatar_for`メソッドに`size`属性を与えず、メールアドレスがexample@railstutorial.orgである場合、Gravatarのプロフィール画像のURLが`https://secure.gravatar.com/avatar/bebfcf57d6d8277d806a9ef3385c078d?s=80`となります。

`gravatar_for`メソッドの`size`属性に値`50`を与えた場合、Gravatarのプロフィール画像のURLは`https://secure.gravatar.com/avatar/bebfcf57d6d8277d806a9ef3385c078d?s=50`とります。

### オプションハッシュとキーワード引数の違い

「オプションハッシュの場合、引数の組がハッシュとしてひとかたまりにされており、ハッシュそのものを別のメソッドに渡すこともできる。一方のキーワード引数は、引数そのものはひとまとまりのオブジェクトにされていない。」というのが大きな違いかと思います。「別メソッドにオプションハッシュそのものを渡すことにより、呼び出し側のメソッドの内部構造を知らなければならなくなる。これはメソッド同士の結合度が高くなってよろしくない」という問題は考えられます。