空白スペースが+になる理由（railsソースコードリーディング）

## 環境
- rails 4.2.0
- ruby 2.2.3

## 状況
railsにおいて

```index.erb
= link_to new_xxx_path(title: 'なぜか デコードできない')
```

とすると、htmlにおいて

```index.erb
<a href="/xxx/new?title=%E3%81%AA%E3%81%9C%E3%81%8B+%E3%83%87%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84">
```
というリンクになっている。このままこのリンクを踏んで、遷移先において

```new.erb
= params[:title]
```
とすると、

```
なぜか+デコードできない
```
と表示されてしまう。空白スペースがいつの間にかplus(+)に変わってしまい、デコードする時に、plus(+)がそのままになってしまっているという問題。

## 背景
そもそもHTTPにおいて、GETやPOSTのパラメーターはapplication/x-www-form-urlencodedという形式に変換されるものである。

application/x-www-form-urlencodedという形式に関しては
https://wiki.suikawiki.org/n/application%2Fx-www-form-urlencoded
あたりを参考に。

大事なことは、application/x-www-form-urlencodedという形式に沿ってエンコードすると、 <b>空白スペースが「+」に変換される</b>ということである。

## 原因
さて、railsにおいていつapplication/x-www-form-urlencodedという形式にparameterが変換されてしまうかを探る旅に出るとしよう。

rails自体を探るためにrailsのソースコードを引っ張ってきた。
https://github.com/rails/rails

```linux
.
├── actioncable
├── actionmailer
├── actionpack
├── actionview
├── activejob
├── activemodel
├── activerecord
├── activesupport

```
メインっぽいのをあげたが、この中で今回見るのは、 ``` actionpack ``` 。

actionpackの中は以下のようになっていて、このうち、 ``` action_dispatch ``` という部分に着目して原因の追究を進める。

```linux
.
├── CHANGELOG.md
├── MIT-LICENSE
├── README.rdoc
├── Rakefile
├── actionpack.gemspec
├── bin
│   └── test
├── lib
│   ├── abstract_controller
│   ├── abstract_controller.rb
│   ├── action_controller
│   ├── action_controller.rb
│   ├── action_dispatch
│   ├── action_dispatch.rb
│   ├── action_pack
│   └── action_pack.rb
└── test
    ├── abstract
    ├── abstract_unit.rb
    ├── assertions
    ├── controller
    ├── dispatch
    ├── fixtures
    ├── journey
    ├── lib
    ├── routing
    └── tmp

```

### action_dispatchとは

>Action Dispatchはwebリクエストに関する情報を解析して、ユーザによって定義された通りルーティングの処理をする。 そして
>
- MIME-type negotiation
- POSTやPATCH、PUT本体内のパラメータのデコード
- HTTP キャッシングロジック、クッキー、セッションの処理

>といったようなHTTPに関連したより高度な処理をする

http://tkymtk.hatenablog.com/entry/2013/10/29/073538

ざっと言うと、こんな感じの役割を果たしているそうなので、まさに今回の問題に絡む張本人といった感じである。

### ソースコードリーディング
そして、関連するソースコードは、

```linux
├── lib
│   ├── action_dispatch
│   │   └── testing
│   │       ├── integration.rb
```
ここにある。integration.rbの中にある。
integration.rbを読んでいくと、関連する部分は以下のようになっている。

```action_dispatch.rb
module ActionDispatch
  module Integration
    module RequestHelpers
      def get(path, *args)
        process_with_kwargs(:get, path, *args)
      end
			
      class Session
        private
          def process_with_kwargs(http_method, path, *args)
            if kwarg_request?(args)
              process(http_method, path, *args)
            else
              non_kwarg_request_warning if args.any?
              process(http_method, path, { params: args[0], headers: args[1] })
            end
          end
          REQUEST_KWARGS = %i(params headers env xhr)
          def kwarg_request?(args)
            args[0].respond_to?(:keys) && args[0].keys.any? { |k| REQUEST_KWARGS.include?(k) }
          end
          def process(method, path, params: nil, headers: nil, env: nil, xhr: false)
            ...

            request_env = {
              ...

              :params => params,

              ...

              "CONTENT_TYPE" => "application/x-www-form-urlencoded",

              ...
            }
          end
      end
    end
  end
end
```
というわけで、ここでencodeに関することを規定していたわけである。

### 原因のまとめ
以上のことからわかったのは、

```index.erb
new_xxx_path(title: 'なぜか デコードできない')
```
と記述すると、gemの方に送られて、application/x-www-form-urlencodedの形式でエンコードされるという指定を受けたurlが返ってくるわけである。

なので、空白スペースが勝手に+に変換されてしまったように見えたのである。

## まとめ
+を無理やり変更するには、

```index.erb
new_xxx_path(title: 'なぜか デコードできない')
```
で返ってきた値の中の+を ``` %20 ``` に変えるコードを記述する

```index.erb
= link_to '新規作成', new_xxx_path(title: 'なぜか デコードできない').gusb("+", "%20")
```

とか、デコードするコードをapplication/x-www-form-urlencodedの形式でデコードするものに修正

```
= URI.decode_www_form_component("%E3%81%AA%E3%81%9C%E3%81%8B+%E3%83%87%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84")

# => "なぜか デコードできない"
```

すればなんとかできなくもないということである。