Railsチュートリアル：10章(わからないとこメモです)

さて10章です。

わからないとこメモだけにしていきます。


###第10章 ユーザーの更新・表示・削除

第8章で実装した認証用のコードを使うとのこと。さっそくこれがなんの話だったか分からない。

##10.1 ユーザーを更新する

POSTリクエストに応答するcreateの代わりに、PATCHリクエストに応答するupdateアクションを作成
この辺でプロゲートとまず乖離、パッチリクエストとは。

##10.1.1 編集フォーム

Gravatarへのリンクでtarget="_blank"が使われていますが、これを使うとリンク先を新しいタブ (またはウィンドウ) で開くようになるので、別のWebサイトへリンクするときなどに便利です (ただしtarget="_blank"にはセキュリティ上の小さな問題もあります。詳しくは10.1.1.1の演習で見ていきましょう

なるほど。別タブリンクはこいつで。

```
<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>
```

表示ページのURLをみると隠し属性がある。

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

WebブラウザはネイティブではPATCHリクエスト (表 7.1でRESTの慣習として要求されている) を送信できないので、RailsはPOSTリクエストと隠しinputフィールドを利用してPATCHリクエストを「偽造」しています。
へえー。

##10.1.2 編集の失敗

update_attributesへの呼び出しでuser_paramsを使っていることに注目してください。7.3.2でも説明したように、ここではStrong Parametersを使ってマスアサインメントの脆弱性を防止しています。

↑なんのこっちゃかよくわからん。


##10.1.3 編集失敗時のテスト

##10.1.4 TDDで編集を成功させる

パスワードのバリデーションに対して、空だったときの例外処理を加える必要があります。こういったときに便利なallow_nil: trueというオプションがあるので、これを validatesに追加します 

```
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
```

新規ユーザー登録時に空のパスワードが有効になってしまうのかと心配になるかもしれませんが、安心してください。6.3.3で説明したように、has_secure_passwordでは (追加したバリデーションとは別に) オブジェクト生成時に存在性を検証するようになっているため、空のパスワード (nil) が新規ユーザー登録時に有効になることはありません。(空のパスワードを入力すると存在性のバリデーションとhas_secure_passwordによるバリデーションがそれぞれ実行され、2つの同じエラーメッセージが表示されるというバグがありましたが (7.3.3)、これで解決できました。)

↑不明

ここでテスト。説明に反してエラーがでたが無視してすすむことにする。

##10.2 認可

##10.2.1 ユーザーにログインを要求する

転送させる仕組みを実装したいときは、Usersコントローラの中でbeforeフィルターを使います。beforeフィルターは、before_actionメソッドを使って何らかの処理が実行される直前に特定のメソッドを実行する仕組みです4。今回はユーザーにログインを要求するために、リスト 10.15のようにlogged_in_userメソッドを定義してbefore_action :logged_in_userという形式で使います。

ふむ、ここでbefore_action

そろそろテストを自分でかくということのむずさを理解し始める。
現状まったく書いてないのに、かくことの大変さを感じ始める。


##10.2.2 正しいユーザーを要求する

まずはユーザーの情報が互いに編集できないことを確認するために、サンプルユーザーをもう一人追加します。ユーザー用のfixtureファイルに2人目のユーザーを追加

```
# 渡されたユーザーがログイン済みユーザーであればtrueを返す
  def current_user?(user)
    user == current_user
  end
```

```
redirect_to(root_url) unless current_user?(@user)
```

もうこの辺はわけわからん。なんかみたことある理屈だから過去の知識が定着してないからということだけはわかる。

##10.2.3 フレンドリーフォワーディング

ログインしていないユーザーが編集ページにアクセスしようとしていたなら、ユーザーがログインした後にはその編集ページにリダイレクトされるようにするのが望ましい動作です。リダイレクト先は、ユーザーが開こうとしていたページにしてあげるのが親切というものです。

なるほど。

ユーザーを希望のページに転送するには、リクエスト時点のページをどこかに保存しておき、その場所にリダイレクトさせる必要があります。この動作をstore_locationとredirect_back_orの2つのメソッドを使って実現してみましょう

なるほど

##10.3 すべてのユーザーを表示する

来ユーザー数が膨大になってもindexページを問題なく表示できるようにするためのユーザー出力のページネーション (pagination=ページ分割) の方法を学びます。

なるほど

##10.3.1 ユーザーの一覧ページ

index.html.erb

なんの説明もないが手動でビューを作成しろということと理解。

まあここはプロゲートとにてるのでコードの中身は意味不明でも構造としては理解しやすい。

##10.3.2 サンプルのユーザー

```
gem 'faker',          '1.7.3'
```
フェイクユーザーを追加可能。
今回は本番環境にも適用させる。

```
$ rails db:migrate:reset
$ rails db:seed
```

これでフェイクユーザー作成。
ちなみにコマンド後でてきたのは

```
ec2-user:~/environment/sample_app (updating-users) $ rails db:migrate:reset
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
== 20200505013551 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0031s
== 20200505013551 CreateUsers: migrated (0.0036s) =============================

== 20200505042250 AddIndexToUsersEmail: migrating =============================
-- add_index(:users, :email, {:unique=>true})
   -> 0.0027s
== 20200505042250 AddIndexToUsersEmail: migrated (0.0032s) ====================

== 20200505044314 AddPasswordDigestToUsers: migrating =========================
-- add_column(:users, :password_digest, :string)
   -> 0.0032s
== 20200505044314 AddPasswordDigestToUsers: migrated (0.0037s) ================

== 20200506073130 AddRememberDigestToUsers: migrating =========================
-- add_column(:users, :remember_digest, :string)
   -> 0.0064s
== 20200506073130 AddRememberDigestToUsers: migrated (0.0070s) ================

ec2-user:~/environment/sample_app (updating-users) $ rails db:seed
ec2-user:~/environment/sample_app (updating-users) $ 
```

seedのあとはなにもでない

本当に作成されてるのか不安なので、クラウド９のプレビュー環境で確認。
しようとするとログインが必要、そらそうかということで
作成されたはずの
             email: "example@railstutorial.org",
             password:              "foobar",
こちらでログインできました。ちゃんとたくさん作成されてました。


##10.3.3 ページネーション

Railsには豊富なページネーションメソッドがあります。今回はその中で最もシンプルかつ堅牢なwill_paginateメソッドを使ってみましょう。

ふむ。

will_paginateメソッドは少々不思議なことに、usersビューのコードの中から@usersオブジェクトを自動的に見つけ出し、それから他のページにアクセスするためのページネーションリンクを作成しています。ただし、リスト 10.45のビューはこのままでは動きません。というのも、現在の@users変数にはUser.allの結果が含まれていますが (リスト 10.36)、will_paginateではpaginateメソッドを使った結果が必要だからです。

ふむ

paginateでは、キーが:pageで値がページ番号のハッシュを引数に取ります。User.paginateは、:pageパラメーターに基いて、データベースからひとかたまりのデータ (デフォルトでは30) を取り出します。したがって、1ページ目は1から30のユーザー、2ページ目は31から60のユーザーといった具合にデータが取り出されます。ちなみにpageがnilの場合、 paginateは単に最初のページを返します。

paginateを使うことで、サンプルアプリケーションのユーザーのページネーションを行えるようになります。具体的には、indexアクション内のallをpaginateメソッドに置き換えます (リスト 10.46)。ここで:pageパラメーターにはparams[:page]が使われていますが、これはwill_paginateによって自動的に生成されます。

ふむ

よって

```
@user=user.all
```
を

```
@users = User.paginate(page: params[:page])
```

なるほど。

ページ遷移ボタン誕生、いやーレイルズってすごいなぁぁ


##10.3.4 ユーザー一覧のテスト

リスト 10.23で2人目のユーザーをfixtureに追加しましたが、今回はもっと多くのユーザーを作成する必要があります。手動で追加するのは面倒そうですね。幸運にも、ユーザー用fixtureファイルのpassword_digest属性で使ったように、fixtureでは埋め込みRubyをサポートしています。これを利用してさらに30人のユーザーを追加してみましょう 

なるほどぉ

この節でのテスト内容は、、、

今回のテストでは、ログイン、indexページにアクセス、最初のページにユーザーがいることを確認、ページネーションのリンクがあることを確認、といった順でテストしていきます。最後の2つのステップでは、テスト用のデータベースに31人以上のユーザーがいる必要があります。

とのこと。でこのコードが

```ruby
require 'test_helper'

class UsersIndexTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end

  test "index including pagination" do
    log_in_as(@user)
    get users_path
    assert_template 'users/index'
    assert_select 'div.pagination'
    User.paginate(page: 1).each do |user|
      assert_select 'a[href=?]', user_path(user), text: user.name
    end
  end
end
```
こうなると。

これをセルフでかけないといけないというとぞっとする。
※カラーに仕方をおぼえました

##10.3.5 パーシャルのリファクタリング

ここは全く理解不能。
このリファクタリングの立て付けは数回みたが相変わらず謎

##10.4 ユーザーを削除する

##10.4.1 管理ユーザー

管理者権限adminを追加。
それ用のデータベースからむも追加

追加したらコンソールで確認

```ruby
$ rails console --sandbox
>> user = User.first
>> user.admin?
=> false
>> user.toggle!(:admin)
=> true
>> user.admin?
=> true
```

ここではtoggle!メソッドを使って admin属性の状態をfalseからtrueに反転しています。

急にtoggle!は？？です。


##10.4.2 destroyアクション

とくになし

##10.4.3 ユーザー削除のテスト

ここの最後のテストも意味不明

なんとさいごのテストで

```ruby
ec2-user:~/environment/sample_app (updating-users) $ rails test
Running via Spring preloader in process 10374
Started with run options --seed 36874

ERROR["test_index_as_admin_including_pagination_and_delete_links", UsersIndexTest, 0.17700017599963758]
 test_index_as_admin_including_pagination_and_delete_links#UsersIndexTest (0.18s)
NoMethodError:         NoMethodError: undefined method `email' for nil:NilClass
            test/test_helper.rb:27:in `log_in_as'
            test/integration/users_index_test.rb:10:in `block in <class:UsersIndexTest>'

ERROR["test_index_as_non-admin", UsersIndexTest, 0.18171667800015712]
 test_index_as_non-admin#UsersIndexTest (0.18s)
NoMethodError:         NoMethodError: undefined method `email' for nil:NilClass
            test/test_helper.rb:27:in `log_in_as'
            test/integration/users_index_test.rb:27:in `block in <class:UsersIndexTest>'

ERROR["test_should_redirect_destroy_when_logged_in_as_a_non-admin", UsersControllerTest, 0.8853418700000475]
 test_should_redirect_destroy_when_logged_in_as_a_non-admin#UsersControllerTest (0.89s)
AbstractController::ActionNotFound:         AbstractController::ActionNotFound: The action 'destroy' could not be found for UsersController
            test/controllers/users_controller_test.rb:43:in `block (2 levels) in <class:UsersControllerTest>'
            test/controllers/users_controller_test.rb:42:in `block in <class:UsersControllerTest>'

ERROR["test_should_redirect_destroy_when_not_logged_in", UsersControllerTest, 0.8909336810011155]
 test_should_redirect_destroy_when_not_logged_in#UsersControllerTest (0.89s)
AbstractController::ActionNotFound:         AbstractController::ActionNotFound: The action 'destroy' could not be found for UsersController
            test/controllers/users_controller_test.rb:35:in `block (2 levels) in <class:UsersControllerTest>'
            test/controllers/users_controller_test.rb:34:in `block in <class:UsersControllerTest>'

 FAIL["test_successful_edit_with_friendly_forwarding", UsersEditTest, 1.040912381000453]
 test_successful_edit_with_friendly_forwarding#UsersEditTest (1.04s)
        Expected response to be a <3XX: redirect>, but was a <200: OK>
        test/integration/users_edit_test.rb:32:in `block in <class:UsersEditTest>'

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

Finished in 1.10565s
33 tests, 66 assertions, 1 failures, 4 errors, 0 skips
```

もう紐解けないのでそのままにします。。。



最後、いつものデプロイ。

一点、新しいコマンドが

```ruby
$ heroku pg:reset DATABASE
```

これをやると

```ruby
ec2-user:~/environment/sample_app (master) $ heroku pg:reset DATABASE
 ▸    WARNING: Destructive action
 ▸    postgresql-symmetrical-81529 will lose all of its data
 ▸    
 ▸    To proceed, アプリ名 or re-run this command with --confirm アプリ名

> アプリ名
```

的な忠告がでます。

回答もとめられるので上記のようにアプリ名をいれてください。

以上。