Rails6 のちょい足しな新機能を試す 119（filter_paramters 編)

# はじめに

Rails 6 に追加された新機能を試す第119段。 今回は、`filter_parameters` 編です。
Rails 6 では、 filter_parameters で proc を使って、フィルターしたときに、パラメータが配列になっているときに、フィルターされないというバグが修正されています。

Ruby 2.6.5, Rails 6.0.2.1, Rails 5.2.4.1 で確認しました。 (Rails 6.0.0 でこの修正が入っています。)

```shell
$ rails --version
Rails 6.0.2.1
```

今回は、User を2つ登録する画面を作って、その動作を確認します。
なお、 `filter_parameters` の動作を確認するための手抜き実装になってます。

# Rails プロジェクトを作る

Rails プロジェクトを新たに作成します。

```shell
$ rails new rails_sandbox
$ cd rails_sandbox
```

# User モデルを作る

`name` を持つ User モデルを作成します。

```shell
$ bin/rails g model User name
```

# Controller と View を作る

User の controller と View を作ります。 View は手抜き実装で、 一覧画面 (index) と 登録画面 (new) だけです。

```shell
$ bin/rails g controller Users index new
```

# routes を定義する

User 用にルーティングを定義します。 これまた、手抜き実装で、 `index`, `new`, `create` の3つだけにします。

```ruby:config/routes.rb
Rails.application.routes.draw do
  resources :users, only: %i[index new create]
end
```

# 一覧画面 (index) を作成する

一覧画面を作成します。これまた、 `table` タグも使わない手抜き実装です。

`User` の `name` を1件ずつ表示します。

画面の下に、登録画面へのリンクを表示します。

```ruby:app/views/users/index.html.erb
<h1>Users#index</h1>

<% @users.each do |user| %>
  <p>
    <%= user.name %>
  </p>
<% end %>

<%= link_to 'New', new_user_path %>
```

# 登録画面 (new) を作成する

登録画面を作成します。ここで、今回の機能を試すためにパラメータの値が配列になるようにします。
(結果として2件のデータを登録することになります。)

パラメータが配列となるように、`form.text_field` の引数が `name="names[]"` としていることに注意してください。
これが、今回の機能を試すために必要なことの1つです。

```erb:app/views/users/new.html.erb
<h1>Users#new</h1>

<%= form_with url: users_path do |form| %>
  <p>
    <%= form.text_field name="names[]" %>
  </p>
  <p>
    <%= form.text_field name="names[]" %>
  </p>
  <%= form.submit %>
<% end %>
```

# UsersController を完成させる

今回の機能を確認するために、完成させる必要は無いのですが、一応、動作するように実装します。
これまた、手抜き実装です。

`index` メソッドでは、全データを取得します。
`create` メソッドでは、パラメータを元にして User をデータベースに保存し、一覧画面にリダイレクトします。

```ruby:app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def new
  end

  def create
    params[:names].each do |name|
      User.create(name: name)
    end
    redirect_to users_path
  end
end
```

# filter_parameters を指定して、 names パラメータの値がフィルタリングさせる

いよいよ、今回の機能を確認するために、 `filter_parameters` で `names` パラメータの値をフィルタリングさせます。

proc を追加していることに注意してください。

```ruby:config/application.rb
...
module App
  class Application < Rails::Application
    ...
    config.filter_parameters << lambda do |key, value|
      if key =~ /names/
        value.replace('[FILTERED]') if value.respond_to?(:replace)
      end
    end
  end
end
```

# マイグレーションを実行する

```shell
$ bin/rails db:create db:migrate
```

# rails server を実行して、登録画面から登録する

`bin/rails s` を実行し、 `http://localhost:3000/users/new` にアクセスし、2つのフィールドに適当に入力して、 `Save` ボタンを押します。

このとき、コンソールでは、 `names` パラメータが、 `[FILTERED]` となっていることに注意してください。

```
Started POST "/users" for 192.168.16.1 at 2020-01-25 02:48:55 +0000
Processing by UsersController#create as JS
  Parameters: {"authenticity_token"=>"..., "names"=>["[FILTERED]", "[FILTERED]"], "commit"=>"Save "}
     (0.2ms)  BEGIN
```

# Rails5 では

Rails 5.2.4.1 では、 フィルターされず、そのまま画面で入力した値が表示されてしまいます。

```
Started POST "/users" for 192.168.0.1 at 2020-01-25 01:42:25 +0000
Processing by UsersController#create as JS
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"..., "names"=>["aaa", "bbb"], "commit"=>"Save "}
```

# あくまで手抜きのコードです

実際のアプリでは、複数のデータを1つの画面で登録する場合には、 Form オブジェクトを使ったり、Validation を追加したり、Strong Paramters を使ったりすると思います。
今回は、あくまでも、機能の確認のための実装なので、そういった点は、すっとばして、手を抜いてます。
このままコードを再利用することはオススメしません。

# 試したソース

https://github.com/suketa/rails_sandbox/tree/try119_filter_parameters_proc


# 参考情報

* [Add support for Proc based parameter filtering on arrays of values](https://github.com/rails/rails/pull/36370)