わたしがRailsチュートリアルで学んだこと【7章】

* 注意：プログラミング歴32日の初心者が書いています

* 注意：間違っていたら優しく教えてください（喜びます）

「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
 https://railstutorial.jp/

素晴らしいチュートリアルに感謝します。

#7.1.1 デバッグとRails環境

##デバッグとは
バグを見つけて、排除すること。


```rb
if Rails.env.development?
    # 開発環境
end

if Rails.env.production?
    # 本番環境
end
```

デバッグ情報は本番環境では表示させたくないので、`if Rails.env.development?`が`true`つまり開発環境でのみ表示させるようにします。

```rb
debug(params) if Rails.env.development?
```

`debug`メソッドを使用すると、デバッグ情報にアクセスできます。

`params`はRailsから送られてきた値を受け取るためのメソッドです。


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

viewに表示させると、上記のようなデバッグ情報を見ることができます。


##Sassのミックスイン機能について

```sass
@mixin box_sizing {
  -moz-box-sizing:    border-box;
  -webkit-box-sizing: border-box;
  box-sizing:         border-box;
}
.
.
/* miscellaneous */
.debug_dump {
  @include box_sizing;
}
```

`@mixin`という機能を使えば、CSSのセットをあらかじめ作っておいて、他の要素で読み込ませることができます。
読み込みには`@include`を使います。


#7.1.2 Usersリソース

Userモデルのデータベースに登録されたユーザーにアクセスする際は、ユーザーのidを使用して、HTTPリクエストをします。

例えば、idが１のユーザーの情報は、`/users/1`というURLでリクエストしたいということです。

これを有効にするために、ルーティングに以下を追加します。

```rb
resource :users
```

この`resource`はRailsの機能で、以下のルーティングを自動で設定してくれます。

| Prefix | Verb | URI Pattern | Controller#Action |
|:--|:--|:--|:--|
| users | GET | /users(.:format) | users#index |
| |POST | /users(.:format) | users#create |
| new_user | GET | /users/new(.:format) | users#new |
| edit_user | GET | /users/:id/edit(.:format) | users#edit |
| user | GET | /users/:id(.:format) | users#show |
| |PATCH | /users/:id(.:format) | users#update |
| |PUT | /users/:id(.:format) | users#update |
| |DELETE | /users/:id(.:format) | users#destroy |


###ユーザーページの表示（showアクション）

`resource`によってルーティングが設定されたので、`/users/1`のような`モデル+id`のURLで、showアクションにアクセスできます。

ルーティングがshowアクションへのリクエストを検知して、コントローラへ割り振ります。
コントローラを見てみると、showアクションが定義されていないので、定義します。

```rb
class UsersController < ApplicationController

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

end
```

showアクション内では、インスタンス変数`@user`を定義しています。
`User`データベースの中から`.find`メソッドを使って特定のユーザー情報を取り出そうとしています。


###`params[:id]`について

paramsで受け取るデータは、getのクエリパラメータとPostでformを使って送信されるデータの2つです。

| Prefix | Verb | URI Pattern | Controller#Action |
|:--|:--|:--|:--|
| user | GET | /users/:id(.:format) | users#show |

showアクションは、上記です。
URLで、idを指定していますので、このidを`params[:id]`で受け取っています。


これで、user/id というURLから、個別のユーザーページを表示させることができるようになりました。


#7.2.1 form_forを使用する

form_forについては以下がわかりやすい。
「【Rails】form_forの使い方を徹底解説！」
https://www.pikawaka.com/rails/form_for

form_forをつかうことで、HTMLのformタグ周りを生成し、さらにデータの送信・保存やセキュリティ面も強化してくれる。

```erb
<%= form_for('モデルのインスタンス') do |f| %>
  フォーム内容
<% end %>
```

上記のようにして使う。

```rb
def new
  @user = User.new
end
```

引数にインスタンス変数を指定し、モデルのクラスをform_forに知らせます。

モデルのインスタンスはコントローラで定義する。ここでインスタンスに何も中身がなければ、Railsが自動でcreateアクションに振ってくれる。情報がすでにあるインスタンスの場合は、自動でupdateアクションに振ってくれる。

```erb
<%= form_for(@user) do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>
```

「f.htmlタグ名 :データベースのカラム名」と指定します。 
つまり上の例だとusersテーブルのnameカラムに投稿した内容が送られることなります。 
送信ボタンは「f.submit」とするだけで作成されます。

```erb
<input type="text" name="user[name]" id="user_text" />
```

また、生成されたinputタグにはname属性も自動で付与されます。
Railsはnameの値をparamsで受け取って処理を行うためです。


#7.3.1 正しいフォーム

```rb
class UsersController < ApplicationController

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

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])    # 実装は終わっていないことに注意!
    if @user.save
      # 保存の成功をここで扱う。
    else
      render 'new'
    end
  end
end
```

formを送信すると、コントローラの`create`メソッドが動くよう設定します。
送信されたデータは、`params`で受け取るのでした。

`@user.save`がtrueであれば、そのままsave。
`@user.save`がfalseであれば、newメソッドへレンダリングします。（新規登録のやり直し）

paramsで受け取ったデータは、たとえば以下のようなハッシュになっています。

```rb
{"user" => { "name" => "Foo Bar",
            "email" => "foo@invalid",
            "password" => "[FILTERED]",
            "password_confirmation" => "[FILTERED]"
          }
}
```


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

二重ハッシュになっているので、params[:user]で取り出して@userに格納。

これは、以下のコードと同じ内容です。

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


#7.3.2 Strong Parameters

ユーザーからの悪意あるデータ送信を防ぐために、Strong Parametersというテクニックを使用します。

Userモデルに今後追加するかもしれない重要な属性を書き換えられないように、送信できるデータ属性を限定します。

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

createメソッドでは、直接paramsの値を呼び出すことはしません。
その代わり、`user_params`メソッドを呼び出します。

`user_params`メソッドでは、paramsに渡すデータを、userクラスの、限られた属性のみを許可しています。
これによって、必要のないデータや悪意のあるデータをparamsが受け取らないようにしています。

また、`private`キーワードを使用することで、このメソッドには外部からのアクセスができないようになります。


#7.3.4 失敗時のテスト

```rb
assert_no_difference 'User.count' do
  post users_path, params: { user: { name:  "",
                                     email: "user@invalid",
                                     password:              "foo",
                                     password_confirmation: "bar" } }
end
```

`assert_no_difference`メソッドは、ブロック（do ~ end）の実行前と実行後で、引数`User.count`が変わらないことをテストしています。

`User.count`はユーザー数のことです。`users_path`に`post`リクエストを送信しています。
送信するデータはinvalidであるべきものですので、Userの登録が完了して`User.count`が増えてはいけません。


#7.4.1 登録フォームの完成

##flash変数について

ユーザーの登録に完了した際などに、1度きり表示するメッセージの設定に使用します。
`render_to`などと一緒に使われることが多いです。

コントローラでflashメッセージをkeyとvalue形式で設定し、ビューからflashをハッシュのように呼び出します。



#7.4.4 成功時のテスト