railsチュートリアル7章進めたときの覚書

##この章では何するの？
ユーザー登録機能を追加するよ
HTML フォームを使ってWebアプリケーションに登録情報を送信
ユーザーを新規作成して情報をデータベースに保存
作成されたユーザーの新しいプロフィールを表示できるようにするために、ユーザーを表示するためのページを作成

ユーザー用のRESTアーキテクチャを実装する第一歩を踏み出すよ

##サイトにdebug情報の追加
ビルトインの `debug`メソッドと`params`変数を使い、デバッグ用の情報が表示されるようになる。


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

開発環境だけでdebug情報を出力したいときは下記コード追加。

```
if Rails.env.development?
```

logサンプル

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

##Usersリソース
RESTの原則に従う場合、リソースへの参照はリソース名とユニークなIDを使うのが普通
ユーザーをリソースとみなす場合、id=1のユーザーを参照するということは、/users/1というURLに対してGETリクエストを発行するということを意味する。

users/1 のurlを有効にするために下記追加

```rb:config/routes.rb
  resources :users
```

ユーザーのURLを生成するための多数の名前付きルート（5.3.3）と共に、RESTfulなUsersリソースで必要となるすべてのアクションが利用できるようになる

プロフィール表示用のviewファイルの作成

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

Usersコントローラに `show` アクション追加

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

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

  def new
  end
end
```

##debuggerメソッド
コントローラーに`debugger`を追加すると、railsのコンソール上でデバッグできる

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

  def show
    @user = User.find(params[:id])
    debugger #これ追加
  end

  def new
  end
end
```

`ctrl + d`で抜けれる

##formの実装
`form_with`ヘルパーメソッドを使用する

##エラーメッセージについて
railsは無効な内容の送信によって元のページに戻されると、CSSクラス`field_with_errors`を持ったdivタグでエラー箇所を自動的に囲んでくれる機能がある。

##form用のテスト

```
#コントローラーの作成
$rails generate integration_test users_signup
```

ユーザー登録ボタンを押したときに（ユーザー情報が無効であるために）ユーザーが作成されないことを確認する。

getメソッドを使ってユーザー登録ページにアクセス
`get signup_path`

フォーム送信をテストするためには、 users_pathに対してPOSTリクエストを送信する

##flash
登録完了後に表示されるページにメッセージを表示し（この場合は新規ユーザーへのウェルカムメッセージ）、2度目以降にはそのページにメッセージを表示しないようにする。

上記のような情報を表示するためにrailsでは、flashという特殊な変数を使う。

flash変数に代入したメッセージは、リダイレクトした直後のページで表示できるようになる。

##ユーザーが作成されたことを確認するテスト
`assert_difference`メソッドを使いテストする

`assert_no_difference`と同様に、このメソッドは第一引数に文字列（'User.count'）を取り、`assert_difference`ブロック内の処理を実行する直前と、実行した直後のUser.countの値を比較する。

ここで`rails t`したら下記のエラーが出た

```
ERROR["test_invalid_signup_information", #<Minitest::Reporters::Suite:0x000055eba2f5b2c8 @name="UsersSignupTest">, 1.2418686970013368]
 test_invalid_signup_information#UsersSignupTest (1.24s)
Nokogiri::CSS::SyntaxError:         
Nokogiri::CSS::SyntaxError: unexpected '#' after '[#<Nokogiri::CSS::Node:0x000055eba2f4a4f0 @type=:ELEMENT_NAME, @value=["div"]>]'
            test/integration/users_signup_test.rb:14:in `block in <class:UsersSignupTest>'

Finished in 1.31543s
15 tests, 30 assertions, 0 failures, 1 errors, 0 skips
```
エラーを吐いているコードはどうやら下記で、`CSS::SyntaxError`と出ているのでcss周りのエラーの模様。

```rb:users_signup_test.rb
assert_select 'div#<CSS id for error explanation>'
assert_select 'div.<CSS class for field with error>'
```

`assert_select`は、特定のHTMLタグが存在するかどうかをテストするメソッドだった。
そのため、下記のように修正。無事テストがとおる。

```rb:users_signup_test.rb
#error explanationのid名を指定
assert_select 'div#error_explanation'

#field with errorのときのクラス名を指定
assert_select 'div.field_with_errors'
```

##本番環境でのSSL
この章で制作したユーザー登録フォームで送信すると、名前やメールアドレス、パスワードといったデータがネットワーク越しに流されていく。
これを修正するために、Transport Layer Security（TLS）を使う。
TLS: ローカルのサーバーからネットワークに流れる前に、大事な情報を暗号化する技術

方法
`production.rb`に一行修正を加える
具体的には、`config`に「本番環境ではSSLを使うようにする」という設定をする

```rb:config/environments/production.rb
config.force_ssl = true #一行追加
```

次に、遠隔にあるサーバーのSSLをセットアップする。
本番用のWebサイトでSSLを使えるようにするためには、ドメイン毎にSSL証明書を購入し、セットアップする必要がある。
証明書周りは工数かかるが、HerokuのSSL証明書に便乗する方法でその作業をせずに済む。
独自ドメインの場合は証明書周りの作業必要。

##本番環境用のサーバー
WEBrickをPumaに置き換える。
理由は、WEBrickは簡単にセットアップできたり動せることが特長だが、著しいトラフィックを扱うことには適していないため。
Pumaは多数のリクエストを捌くことに適したRuby/Rackアプリケーション用のサーバーである。

Pumaのファイルを書き換え

```
# Pumaの設定ファイル
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { ENV['RACK_ENV'] || "production" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
workers ENV.fetch("WEB_CONCURRENCY") { 2 }
preload_app!
plugin :tmp_restart
```

`./Procfile`を制作

```:Procfile
web: bundle exec puma -C config/puma.rb
```

DBを本番向けに設定

```yml:config/database.yml
#下記追加
production:
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://railsguides.jp/configuring.html#データベース接続をプールする
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: sample_app_production
  username: sample_app
  password: <%= ENV['SAMPLE_APP_DATABASE_PASSWORD'] %>
```