Railsチュートリアル 第７章

#デバッグ
###debugメソッド
debugメソッドとparams変数を使い、各ページにデバッグ情報が表示されるようにする。

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

Railsにはテスト環境（test）、開発環境（development）、本番環境（production）の３つのデフォルト環境が用意されている。
上記では、開発環境にのみデバッグ情報を表示されるようにしている。

###debuggerメソッド
上記ではdebugメソッドを書きましたが、もっと直接的にデバッグする方法として、
byebug gemによるdebuggerメソッドがあります。

debuggerメソッドをUsersコントローラーに差し込む

```ruby:users_controller.rb
class UsersController < ApplicationController

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

  def new
  end
end
```

debuggerメソッドを差し込んだら、ブラウザから/users/1にアクセスすると、
Railsサーバーを立ち上げたターミナルにはbyebugプロンプトが表示される。

```
(byebug)
```

このプロンプトに対して、Railsコンソールのように状態を確認することが可能となる。

```
(byebug) @user.name
"Example User"
(byebug) @user.email
"example@railstutorial.org"
(byebug) params[:id]
"1"
```

#フォームHTML

```html:new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user) 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_confirmaiton , "Confirmation" %>
      <%= f.password_field :password_confirmaiton %>
      
      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>
```

###form_forメソッド
form_forとは、Railsでフォームタグを作成するメソッド。
同じようなヘルパーとして、form_tagもあるが、基本的にはユーザーの登録や更新はform_forを、検索機能にはform_tagを使用する。

```html:
<%= form_for(モデル,[オプション]) do |f| %>
    フォームの中身
<% end %>
```

例えば、次のコードを実行すると

```html:
<%= f.label :name %>
<%= f.text_field :name %>
```

Userモデルはstring型のnameというカラムを持っているので、f.とすることで、Userモデルとlabelやテキストボックス(text_field)を紐づけることができる。
f.labelは、nameのラベルタグを生成し、f.text_fieldは、nameのテキストボックスを生成する。
実際に生成されたHTMLソースは以下のようになる。

```html:
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
```

また、下記を実行すると

```html:
<%= f.submit "Create my account", class: "btn btn-primary" %>
```

f.submitがこのフォームの送信ボタンを生成される。

```html:
<form action="/users" class="new_user" id="new_user" method="post">
```

上記は、/usersに対して、HTTPのPOSTリクエストを送信している。

#Strong Parameters
マスアサインメント脆弱性を回避するための機能。
Rails4以降に提供されるようになった。

###マスアサインメント機能とは
以下のようにRailsではDBの更新系処理で複数のカラムを一括で指定できること。

```ruby
@user = User.new(params[:user])
```

上記は実際には下記とほぼ同じです。

```ruby
@user = User.new(name: "Foo Bar", email: "foo@invalid",
            password: "foobar", password_confirmation: "foobar")
```

###マスアサインメントの脆弱性とは
マスアサインメントはハッシュをそのまま利用します。
例えばユーザーからのリクエストはparams変数にハッシュとして保存されます。
この内容をそのままマスアサインメント機能を利用して設定していた場合に、想定しないカラムを更新されてしまう可能性があります。
	
例えばUserクラスにname、age、adminの３カラムがあり、adminはユーザーの画面からは更新させない管理者権限だとします。
Userの新規登録処理で、以下のようなコードを書いていた場合

```ruby
@user = User.new(params[:user])
@user.save
```

不正リクエストなどによってparamsにadminが含まれていた場合、管理者権限を任意の値に設定されてしまいます。

###マスアサインメントの脆弱性対策
この場合、user_paramsという外部メソッドを使うのが慣習になっている。
このメソッドは適切に初期化したハッシュを返しparams[:user]の代わりとして使われる。

```ruby
class UsersController < ApplicationController
.
.
def create
  @user = User.new(user_params)
  if @user.save
  else
    render 'new'
  end
end

private

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

このuser_paramsメソッドはUsersコントローラの内部でのみ実行され、Web経由で外部ユーザーに晒される必要はないため、privateキーワードを使って外部から使えないようにしている。

```ruby
def <Model名>_params
  params.require(:<Model名>).permit(:<カラム名１>, :<カラム名２>)
end
```

#ユーザー登録失敗時のテスト

```ruby
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_template 'users/new'
  end
end
```

###assert_no_differenceメソッド
assert_no_differenceのブロックを実行する前後で引数の値（User.count）が変わらない事をテストしている。
ブロック内でpostを使い、登録が失敗するユーザ情報をリクエストしている。

#ユーザー登録成功時
###redirect_toメソッド
redirect_toメソッドは、他のURLにリダイレクトする際に使用します。
下記は全て同じ挙動をしますが、下にいくほど省略形になっています。

```ruby
redirect_to "/users/#{@user.id}"　⇨原形
redirect_to user_path(@user.id)
redirect_to user_path(@user)　　⇨オブジェクトのデフォルトとして、idを渡す場合@userに省略可能
redirect_to @user　　　　　　　　⇨redirect_toのデフォルトとして、userオブジェクトが渡されると、user_pathに変える
```

###データベースリセット

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

###登録成功のテスト

```ruby
test "valid signup information" do
    get signup_path
    assert_difference 'User.count', 1 do
      post signup_path, params: { user: { name: "foo",
                        email: "foo@example.com",
                        password: "foobar",
                        password_confirmation: "foobar" } }
    end
    follow_redirect!
    assert_template 'users/show'
  end
end
```

###assert_differenceメソッド
assert_no_differenceはブロック内の処理実行後にユーザーの数は変わらない事を確認しましたが、assert_differenceはその逆で今回は登録前後で差異（１件）がある事を確認している。

###follow_redirect!メソッド
users_pathにPOSTリクエスト（users#create）を送信した後に、follow_redirect!メソッドをすると、POSTリクエストを送信した結果を見て、指定されたリダイレクト先に移動するメソッド。

##content_tagメソッド
HTMLコードの要素を生成することが可能。
構文

```html
content_tag name, content, option
```

```html
<div class="alert alert-<%= message_type %>">
  <%= message %>
</div>
```

上記をcontent_tagで書くと、下記のようになります。

```html
<%= content_tag(:div, message, class: "alert alert-#{message_type}") %>
```

#デプロイ
本章で開発したユーザー登録フォームで送信すると、名前やメールアドレス、パスワードといったデータがネットワーク越しに流されてしまう。
このようなネットワークに流れるデータは途中で捕捉できるため、扱いには注意が必要。
これを修正するためにSSLを使います。これはローカルのサーバからネットワークに流れる前に、大事な情報を暗号化する技術です。

###SSLの有効化
production.rbという本番環境の設定ファイルの１行を修正するのみです。
具体的には、configに「本番環境ではSSLを使うようにする」という設定をするだけです。

```ruby:config/enviroments/production.rb
Rails.application.configure do
  .
  .
  # Force all access to the app over SSL, use Strict-Transport-Security,
  # and use secure cookies.
  config.force_ssl = true　　⇦変更
  .
  .
end
```

###WEBrickをPumaというWebサーバに置き換える
Rails5ではデフォルでPumaが使える。

```ruby:config/puma.rb
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/
  # deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end
```

###Procfile作成
Heroku上でPumaのプロセスを走らせる設定ファイルを作成する。

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