Rails Tutorial 第7章

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

![スクリーンショット 2023-09-12 063534.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/8fc204d1-86ed-61a6-0d68-56ebf3d86a16.png)
↓
![スクリーンショット 2023-09-12 065114.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/c583ad03-6bf2-e6cc-bb53-eb3c6ae843ba.png)


<strong>"controller"=>"static_pages", "action"=>"about"</strong>


2,
>Railsコンソールを開き、データベースから最初のユーザー情報を取得し、変数userに格納してください。その後、puts user.attributes.to_yamlを実行すると何が表示されますか? ここで表示された結果と、yメソッドを使ったy user.attributesの実行結果を比較してみましょう。

```
User.first
  User Load (4.0ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 
#<User:0x00007f61d9d71238
 id: 1,
 name: "Ryohei",
 email: "michael@example.com",
 created_at: Mon, 11 Sep 2023 07:52:30.250238000 UTC +00:00,
 updated_at: Mon, 11 Sep 2023 08:18:39.867071000 UTC +00:00,
 password_digest: "[FILTERED]">
irb(main):003:0> user = User.first
  User Load (0.1ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 
#<User:0x00007f61dc3ca650
...

#-----------------------------------------------------------------------
#演習に沿ってこれを記述
puts user.attributes.to_yaml
---
id: 1
name: Ryohei
email: michael@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: 2023-09-11 07:52:30.250238000 Z
  zone: &1 !ruby/object:ActiveSupport::TimeZone
    name: Etc/UTC
  time: 2023-09-11 07:52:30.250238000 Z
updated_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: 2023-09-11 08:18:39.867071000 Z
  zone: *1
  time: 2023-09-11 08:18:39.867071000 Z
password_digest: "$2a$12$.6op.nLP1IvEzdshZaMcTuRBaH1.IhXYW00wj2GBcfeU9AvJ0vFoe"
=> nil

#-----------------------------------------------------------------------

y user.attributes
---
id: 1
name: Ryohei
email: michael@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: 2023-09-11 07:52:30.250238000 Z
  zone: &1 !ruby/object:ActiveSupport::TimeZone
    name: Etc/UTC
  time: 2023-09-11 07:52:30.250238000 Z
updated_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: 2023-09-11 08:18:39.867071000 Z
  zone: *1
  time: 2023-09-11 08:18:39.867071000 Z
password_digest: "$2a$12$.6op.nLP1IvEzdshZaMcTuRBaH1.IhXYW00wj2GBcfeU9AvJ0vFoe"
=> nil
```

結果は同じになったみたいですね


## 演習2

1，
>埋め込みRubyを使って、マジックカラム (created_atとupdated_at) の値をshowページに表示してみましょう (リスト 7.4)。

```
<%= @user.name %>,<%= @user.email %>,
<br>
<%= @user.created_at %>,<%= @user.updated_at %>
<br>
#横に広がってしまうので勝手にbrタグを追加しています
```

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

```
<%= @user.name %>,<%= @user.email %>,
<br>
<%= @user.created_at %>,<%= @user.updated_at %>
<br>
<%= Time.now %>

```

上記の結果を総合するとこのような画面になります

![スクリーンショット 2023-09-13 065526.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/7f85fb43-258a-ca69-6af3-60f8302d9336.png)


## 演習3

1，
>showアクションの中にdebuggerを差し込み（リスト 7.6）、ブラウザから/users/1にアクセスしてみましょう。次にRailsコンソールを開き、putsメソッドを使ってparamsハッシュの中身をYAML形式で表示してみましょう。（ヒント: 7.1.1.1の演習を参考にしてください。その演習ではdebugメソッドで表示したデバッグ情報を、どのようにしてYAML形式で表示していたでしょうか?


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

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

```
  4|     # debugger
     5|     # デバッグの表示
     6|   end
     7|   
     8|   def new
=>   9|     debugger
    10|   end
    11| end

(ruby) puts @User 
nil
```
@userの中身はnil

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

まずはこちらにてGravatar上にアカウント作成を行いましょう。
https://ja.gravatar.com/

サインアップし、メールアドレスを登録

![gravatarトップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/f277bba9-6b52-2952-7650-8420c05368e6.png)
![メールアドレスのフォーマット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/0d77bd9c-6c4c-139b-b585-0401ec2278dd.png)

送られてきたメールからログインします


![写真選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/0a2b66ed-bd61-7d18-2886-4fe718b54eb2.png)


あとはrails consoleで最初のuserのemail情報に先ほどGravatarで登録したメールアドレスを挿入しましょう

```
rails c
Loading development environment (Rails 7.0.4.3)
user = User.first
  User Load (0.1ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> 
#<User:0x00007f0b6abef718
...
user.update_attribute(:email, "登録したメールアドレス")
```

このようにプロフィール写真に画像が設定されています

![スクリーンショット 2023-09-15 055655.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/cb6cfeba-5675-20d9-696f-ccb2c9ec4d57.png)

<hr>
2,<br>
7.1.4で定義したgravatar_forヘルパーをリスト 7.12のように変更して、sizeをオプション引数として受け取れるようにしてみましょう。正しく変更すると、gravatar_for user, size: 50のように呼び出せるようになります。重要: 改善したヘルパーはこの後の10.3.1で実際に使うので、忘れずに実装しておきましょう。



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

  # 引数で与えられたユーザーのGravatar画像を返す
  def gravatar_for(user, options = { size: 80 })
    size         = options[:size]
    gravatar_id  = Digest::MD5::hexdigest(user.email.downcase)
    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
```
<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <h1>
        <%= gravatar_for @user,size: 50 %>
        <%= @user.name %>
      </h1>
    </section>
  </aside>
</div>
```
画像が小さくなります

![画像小さくなった.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/4fabf789-1665-48cc-ac4c-bf0b416ab47b.png)

<hr>

3,
オプション引数は今でもRubyコミュニティで一般的に使われていますが「キーワード引数（Keyword Arguments）」でも実現できます。先ほど変更したリスト 7.12を、リスト 7.13のように置き換えてもうまく動くことを確認してみましょう。この2つの実装方法はどこが違うのかを考えてみてください。

```
module UsersHelper

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

```
```
    size         = options[:size]
```
これを引数として入れましたね。こちらの方が簡単です

## 演習5

1,
試しに、リスト 7.15のform_withにあるブロック変数fをすべてfoobarに置き換えてみて、結果が変わらないことを確認してみてください。確かに結果は変わりませんが、変数名をfoobarとするのはあまり良い変更ではなさそうですね。その理由について考えてみてください。

こういうことですね
```
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @user) do |foobar| %>
      <%= foobar.label :name %>
      <%= foobar.text_field :name %>

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

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

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

      <%= foobar.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

```
答えは人によって様々ですが
すぐ下のセクションにはこのように書かれています

![スクリーンショット 2023-09-15 065536.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/42edc66f-1cfa-f9b3-a6b9-4887a68b8b59.png)

これを鑑みるとformには慣例的にfという変数を使用している可能性が高く、広く浸透している物だと考えられます。ネット上で検索してみてもformの変数にfを使用しているようです

## 演習6

1，
『HTML編』ではHTMLをすべて手動で書き起こしていますが、formタグは使っていません。その理由を考えてみてください。

私はHTML編を購入していないので中身は見ていません。なので他の方の回答を参考にさせて頂きました

![スクリーンショット 2023-09-15 070645.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/ec5ce095-b7c5-5001-2680-de9943ac43c9.png)

出典　https://kojimanotech.com/2018/07/06/81/#outline__3_1 より


## 演習7

1,
/signup?admin=1にアクセスすると、paramsの中にadmin属性が含まれていることをデバッグ情報で確認してみましょう。

![演習の答え.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/c0b63bf9-9d21-3a93-147b-57c158a38d59.png)

adminが出現します

## 演習7

1,
最小文字数を5に変更すると、エラーメッセージも自動的に更新されることを確かめてみましょう。

```
class User < ApplicationRecord
  before_save { self.email = email.downcase }
  validates:name, presence: true, length: { maximum:50 } 
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  validates :email, presence: true, length: {maximum:255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: true
  has_secure_password
  validates :password, presence: true, length: { minimum: 5 }
#最小文字数を5に変更
end

```

![演習8、画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/2e3ed541-28b3-3919-3607-828e9144af2d.png)

2,
未送信のユーザー登録フォーム（図 7.14）のURLと、送信済みのユーザー登録フォーム（図 7.20）のURLを比べてみると、URLが違っています。その理由を考えてみてください。

rails routesで開くとrouteは以下のようになっています。
![スクリーンショット 2023-09-17 061852.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/e3a8983d-32bf-0fa3-1802-c8726ca9b4db.png)

/usersのURLを表示するのはエラー表示したとき、つまりCreateアクションが実行されたときになります。

```
  def create
    @user = User.new(user_params) 
    if @user.save
    else
      render 'new', status: :unprocessable_entity
    end
  end
```
送信時はこのアクションが実行されます。
renderは'new.html.erb'つまりsignupのページを表示しますが、アクションまで経由しないため、createアクションに設定されている/usersになります。

## 演習8
1,
リスト 7.20で実装したエラーメッセージに対するテストを書いてみてください。どこまで細かくテストするかはお任せします。リスト 7.25にテンプレートを用意しておいたので、参考にしてください。

app/views/shared/error_messages.html.erbの中のidとclassをテストしましょう

```
<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>
```
この中の

- explanation
- alert
- alert-danger

この3つについてテストしましょう

```
require "test_helper"

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                        email: "user@invalid",
                                        password:              "foo",
                                        password_confirmation: "bar" } }
    end
    assert_response :unprocessable_entity
    assert_template 'users/new'
    assert_select 'div#error_explanation'
    assert_select 'div.alert'
    assert_select 'div.alert-danger'
  end
end

```

rails testでエラーが無いことを確認します

## 演習9

1,
有効な情報を送信し、ユーザーが実際に作成されたことを、Railsコンソールを使って確認してみましょう。

この7.4.1でやったコードを使って実際にユーザー登録してみましょう

```
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    # debugger
    # デバッグの表示
  end
  
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params) 
    if @user.save
      redirect_to @user
    else
      render 'new', status: :unprocessable_entity
    end
  end

  private

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

end

```

signupページにて好きなUserを作成してみましょう。

![スクリーンショット 2023-09-18 153358.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/cb160235-27a0-81f5-ed7a-53c8970b0c0e.png)

redirect_toの設定により、user登録後はusers/idのページに遷移するはずです。
![スクリーンショット 2023-09-18 153420.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/7c96caf7-98ce-df76-68a2-f70605ef0351.png)

rails consoleのUser.allなどで実際にuserが登録されているか確認してみましょう。
![スクリーンショット 2023-09-18 153457.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/bd09de4c-ba47-7253-f29e-e7044c3c052f.png)

<hr>
2,リスト 7.26のredirect_to @userをredirect_to user_url(@user)に書き換えても、同じ結果になることを確認してみましょう。


```
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    # debugger
    # デバッグの表示
  end
  
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params) 
    if @user.save
      redirect_to user_url(@user)
    else
      render 'new', status: :unprocessable_entity
    end
  end

  private

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

end

```

同じ結果を得られれば成功です

## 演習10

1,
Railsコンソールを開いて、文字列内の式展開（4.2.1）でシンボルを呼び出してみましょう。例えば"#{:success}"といったコードを実行すると、どんな値が返ってきますか? 確認してみてください。

```
rails c
Loading development environment (Rails 7.0.4.3)
"#{:success}"
=> "success"
```
2,
上の演習で試した結果を参考に、リスト 7.28のflashがどのような結果になるか考えてみてください。

```
"#{flash}"
=> "{:success=>\"It worked!\", :danger=>\"It failed.\"}"
"#{flash[:success]}"
=> "It worked!"
"#{flash[:danger]}"
=> "It failed."
```
#{flash}はすべて文字列として出力されます

## 演習10

Railsコンソールを使って、新しいユーザーが本当に作成されたかどうかをもう一度チェックしてみましょう。結果は、リスト 7.30のようになるはずです。

先ほど登録した情報が表示されればOKです。

![スクリーンショット 2023-09-18 164845.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/d648d6f5-c0f6-e195-7d9b-99c64d70eb9c.png)

2,
自分のメールアドレスでユーザー登録を試してみましょう。既にGravatarに登録している場合、適切な画像が表示されているか確認してみてください。

Gravatarに登録したメールアドレスで新規登録してみましょう。
画像が表示されればOKです。

![スクリーンショット 2023-09-18 165148.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/95d614b3-39e0-cb85-1e9c-2ed6bbe2926a.png)

## 演習11
7.4.2で実装したflashに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.32に最小限のテンプレートを用意しておいたので、参考にしてください（（コードを書き込む）の部分を適切なコードに置き換えると完成します）
※ちなみに、テキストに対するテストはちょっとしたことで壊れやすく、文の量が少ないflashのキーでも同様です。筆者は、多くの場合flashが空でないことだけをテストするようにしています。

以上のことから、リストに"empty?"を挿入してテストするのが良さそうです

```
require "test_helper"

class UsersSignupTest < ActionDispatch::IntegrationTest
  .
  .
  .
  test "valid signup information" do
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                        email: "user@example.com",
                                        password:              "password",
                                        password_confirmation: "password" } }
    end
    follow_redirect!
    assert_template 'users/show'
    assert_not flash. empty?
  end
end

```

2,
本文中でも指摘したように、flash用のHTML（リスト 7.29）は読みにくくなってしまっています。これを、より読みやすくしたリスト 7.33のコードに変更してみましょう。変更が終わったらテストスイートを実行し、正常に動作することを確認してください。なお、このコードでは、Railsのcontent_tagというヘルパーを使っています。

```
<!DOCTYPE html>
<html>
  <%= render 'layouts/rails_default' %>
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
        <% flash.each do |message_type, message| %>
        #こちらのコードに差し替えてください
        <%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
      <% end %>
      <%= yield %>
      <%= render 'layouts/footer' %>
      <%= debug(params) if Rails.env.development? %>
    </div>
  </body>
</html>
```
その後、rails testでエラーが出なければOKです

3,
リスト 7.26のリダイレクトの行をコメントアウトすると、テストが失敗することを確認してみましょう。

```
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    # debugger
    # デバッグの表示
  end
  
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params) 
    if @user.save
      flash[:success] = "Welcome to the Sample App!"
    　#コメントアウトする
      # redirect_to @user
    else
      render 'new', status: :unprocessable_entity
    end
  end

  private

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

end

```
その後rails testでエラーすることを確認しましょう


4,
リスト 7.26で、@user.saveの部分をfalseに置き換えたとしましょう（バグを埋め込んでしまったと仮定してください）。このとき、assert_differenceのテストではどのようにしてこのバグを検知するでしょうか? テストコードを追って考えてみてください。

試しにemail部分の@を抜いてみましょう

```
require "test_helper"

class UsersSignupTest < ActionDispatch::IntegrationTest
  
  test "valid signup information" do
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                        email: "userexample.com",
                                        password:              "password",
                                        password_confirmation: "password" } }
    end
    follow_redirect!
    assert_template 'users/show'
    assert_not flash. empty?
  end
end
```

```
rails t
Started with run options --seed 24979

 FAIL UsersSignupTest#test_valid_signup_information (1.21s)
        "User.count" didn't change by 1.
        Expected: 1
          Actual: 0
        test/integration/users_signup_test.rb:6:in `block in <class:UsersSignupTest>'

  19/19: [=======================================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.20781s
19 tests, 39 assertions, 1 failures, 0 errors, 0 skips
```

User.countが変わらなかったのでエラーが出ました


## 演習12

1，ブラウザから本番環境にアクセスし、TLSの鍵マークがかかっているか、URLがhttpsになっているかどうかを確認してみましょう

7.5に従いデプロイまでを実行後、確認してみましょう。

![スクリーンショット 2023-09-19 114701.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/502d75d5-0895-3f17-2fa1-1686d6038c22.png)

URL部分に鍵が掛かっていればOKです。

2,
本番環境でユーザーを作成してみましょう。Gravatarの画像は正しく表示されているでしょうか?

renderでデプロイ後、実際にユーザーを登録してみます
![スクリーンショット 2023-09-19 115031.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/af4c5d4d-4334-b8dc-1d28-0ffdce4e33c6.png)

アカウントを作成出来たらOKです

![スクリーンショット 2023-09-19 115055.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3451993/36a4c691-1b2a-5c82-1620-870b2a161618.png)