rails、君に決めた！！~４

一連の記事の目次
[rails、君に決めた！！~目次](https://qiita.com/satousatou/items/d20b61c198a4d439f2e7)

前回の記事
[rails、君に決めた！！~3](https://qiita.com/satousatou/items/d7fa798d858af0ec9cd0)

## コントローラ
#### コントローラの命名規則
`リソースの複数形Controller`
リソースがpersonの時はPeopleController

複数形分からないよって時は`pluralize`を使う

```
$ bin/rails c
Loading development environment (Rails 5.1.5)
[1] pry(main)> 'person'.pluralize
=> "people"
[2] pry(main)> 'chocolate'.pluralize
=> "chocolates"
```

単数形は`singularize`
至れり尽くせりで笑う

#### ApplicationController
全てのコントローラの生みの親
共通処理はここに書く（セキュリティ設定、例外処理、コールバックなど）
app/controllers以下に色々なコントローラが生成されている

#### HTTPリクエストのパラメータを受け取る
HTTPリクエストで利用できるパラメータ送信方法は４種類

```
1. パスパラメータ
2. queryパラメータ
3. Body
4. カスタムヘッダ
```

このうち1,2,3は`params[]`で扱うことができる。
実際にparamsの中身を確認してみよう。
app/controllers/application_controller.rbを下のように変更し、

```ruby

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  # 追加
  def hello
    text = "PARAMS: #{params}"
    render plain: text
  end
end
```

http://localhost:3000/hello?p=foo&q=bar
にアクセスすると、画面に`PARAMS: {"p"=>"foo", "q"=>"bar", "controller"=>"application", "action"=>"hello"}`と表示される。

注意点
`text = "PARAMS: #{params}"`のダブルクオート`""`をシングルクオート`''`にすると、変数の埋め込みができなくなる。。。引っかかったで笑

#### Strong Parameters
強いパラメータとはなんぞや
> Railsアプリに送信されたパラメータを安全に扱うための仕組み

強さとは安全を意味するらしい、真理だ笑

例として、新規ユーザー登録を行う機能について考える。
処理の流れ
`フォーム画面
→userオブジェクトをPOST
→サーバーがデータを適切な形に変換してデータベースに保存`

脆弱性を含む例

```ruby
def create
  # params[:user] => {name: 'Ichiro', email: '~@.com'}
  User.create(params[:user])
end
```

なぜこれはダメなのか。
> 例えば、悪意のあるユーザーがuserオブジェクトに、管理者を意味する{admin: true}のような属性を付加し、サーバーにPOSTしたとする。もしデータベースにadminというカラムが存在していたら、admin属性のユーザーが作成されてしまう。

なるほど、name,email属性だけ送ってくればいいのに悪い人がadmin属性も加えて送って来たりすると管理者権限とられちゃうってことか！

Strong Parametersを使った例

```ruby
def create
  User.create(user_params)
end

private

def user_params
  params.require(:user).permit(:name, :email)
end
```
params[:user]を直接呼ばずにuser_paramsメソッドを呼んでいる。

- requireメソッド
paramsの中にちゃんとuserオブジェクトが必須パラメータとして入っているか検証した後、userの中身を返す
- permitメソッド
更新や追加していい属性をホワイトリスト方式で制限

これでadmin属性を除外できてよきよき。

#### コントローラをもうちょっと詳しく作ってみる

`コントローラ＝アクション＋フィルタ`
アクション：　index,showなどのメソッド
フィルタ：　アクションの前後に共通処理を実行する仕組み



user系を作り直すので、以下のコードを実行する

```ruby
bin/rails d scaffold user
bin/rails db:migrate:reset
```

scaffoldで生成したuserを削除して、データベースもリセット
新たにusers コントローラを作る

```ruby
bin/rails g controller users index show
```

生成されたusres_controller.rbの中身をみてみる。

```ruby
class UsersController < ApplicationController
  def index
  end

  def show
  end
end
```

指定したindex,showアクションあるね、よしよし。
config/routes.rbを変更
ビフォー

```ruby
Rails.application.routes.draw do
  get 'users/index'

  get 'users/show'

  resources :articles
  get 'home/index'
end
```

アフター

```ruby
Rails.application.routes.draw do
  resources :users, only: [:index, :show]

  resources :articles
  get 'home/index'
end
```

ビフォーだとURLがRESTじゃないんだと。

ビフォーのルーティング

```
Prefix Verb        URI Pattern            Controller#Action
users_index GET   /users/index(.:format)   users#index
users_show GET    /users/show(.:format)    users#show
```

アフターのルーティング

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

ルートを見比べてみると確かにって感じだ

#### フィルタを設定する

フィルタは以下の３種類

```
before_action
after_action
around_action
```

前、後ろ、両方ってだけ

実装のイメージ

```ruby
class UsersController < ApplicationController
  before_action :require_login, only: [:index]

  def index
    # 何か処理
  end

  private

  def require_login
    reject_to login_url unless singed_in?
  end
end
```

indexアクションを実行する前にrequire_loginメソッドを実行する。未ログインならindexアクションを実行せず、ログインページに飛ばしてくれる。

引数を取るメソッドをフィルタにしたい場合は、
blockでもフィルタを定義できる

親クラスで定義したフィルタは、子クラスでskip_xxx_actionで例外的に無効化できる

疲れた〜ー
次回はセッション管理！
ついにredisを使うときがきた