Strong_Parametersが機能しないのはform_withとroutingが原因だった

学習メモです。

#Strong_Parametersとは？
Rails４.０以降ではコントローラ層で、Strong Parametersを使うことで、必須のパラメータと許可されたパラメータを指定できる。さらに、paramsハッシュをまるごと渡すとエラーが発生するので、Railsはデフォルトでマスアサインメントの脆弱性から守られる。

###マスアサインメント（mass assignment）とは？
次のように値のハッシュを使ってRubyの変数を初期化すること。

    @user = User.new(params[:user])    # 上記にあるようにRailsはこれをデフォルトでエラーにする

#####上記では、ユーザーが送信したデータを丸ごと受け取っているが、Userモデルに管理者の権限としてのadmin属性というものがあるとすると、送信したデータにadmin属性がtrueになる情報を簡単に紛れさせることができ、管理者権限を渡してしまうことになるのは危険！これがマスアサインメントの脆弱性！


###user_paramsについて
今回のparamsハッシュでは:user属性を必須とし、名前、メールアドレス、重症度、パスワード、パスワードの確認の属性をそれぞれ許可し、それ以外を許可しないようにしたい。

    params.require(:user).permit(:name, :email, :seriousness, :password,
                                  :password_confirmation)

このコードの戻り値は、許可された属性のみが含まれたparamsのハッシュ（:user属性がない場合はエラーに）。

これらのパラメータを使いやすくするために、user_paramsという外部メソッドを使うのが慣習に。このメソッドは適切に初期化したハッシュを返し、params[:user]の代わりとして使われる。

####ここまではRailstutorialで学んだことのまとめです。

#解決したい問題その１ 
##`require(:user)`があるとエラーが発生する

```app/controllers/users_controller.rb
private

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

    param is missing or the value is empty

paramが見当たらないとのこと。

```app/views/users/new.html.erb
    <!-- some long code --!>

    <%= form_with model: @users, local: true do |f| %>
        
      <div class="form-group">
        <%= f.label :name, "ユーザー名" %>
        <%= f.text_field :name, class:"form-control",
            value: @name, required: true, autofocus: true %>
      </div>

    <!-- some long code --!>
```


###form_withの使い方

モデルを渡したときは、URLとスコープが自動推測される。
URL: `@user`がDBに存在するときはupdateアクションに、ないときはcreateアクションに飛ぶ。
　　　今回は存在しないため、createアクションに飛ぶ。
スコープ: `params[:email]` が `params[:user][:email] `に。 

```app/controllers/users_controller.rb
  def new
    @user = User.new
  end
```


#####モデルは`@user`だが、そうするとエラーが起きる。`@users`だとエラーが起きない

```
undefined method `users_path' for #<# <Class:0x00007f9d8198ba18>:0x00007f9d81989178>
Did you mean?  user_path
```

#####`require(:user)`を削除すると、エラーは消えた！
#####けれども、Strong Parametersを使いたいのにそれだと意味がない！！


#解決したい問題その２
##`require(:user)`を実装してのユーザー新規登録test通過

上記だと、エラーは起きなくてもtestで失敗する...

```
test "valid signup information" do
    get signup_path
    assert_difference "User.count",1 do
      post signup_path, params: { user: { name:  "Example",
                            email: "user@example.com",
                            password: "password",
                            password_confirmation: "password" } }
      end
      follow_redirect!
      assert_template "users/show"
      assert_not flash.blank?
  end
  
  
   FAIL["test_valid_signup_information", #<Minitest::Reporters::Suite:0x00007f958a263640 @name="UsersSignupTest">, 0.5420669997110963]
 test_valid_signup_information#UsersSignupTest (0.54s)
        "User.count" didn't change by 1.
        Expected: 1
          Actual: 0
        test/integration/users_signup_test.rb:20:in `block in <class:UsersSignupTest>'

  2/2: [=========================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.58615s
```
####モデルが`@users`だと自動推測が上手くいかず、スコープ: `params[:email]` が `params[:user][:email]`となっていないのかも！なので、 `@users`を`@user`に変更する！

###`users_path`が存在しないエラーだったので、Routingの問題っぽい
```config/routes.rb
    <!-- some long code --!>

  post "users/:id/update", to: "users#update"
  get "users/:id/edit", to: "users#edit", as: :edit
  post "signup", to: "users#create"
  get "signup", to: "users#new"
  get "index", to: "users#index"
  get "users/:id", to: "users#show", as: :user

    <!-- some long code --!>
```
    rails  routes
```

    <!-- some long code --!>

users#update                   POST   /users/:id/update(.:format)                                                              
users#edit                edit GET    /users/:id/edit(.:format)                                                                
users#create            signup POST   /signup(.:format)                                                                        
users#new                      GET    /signup(.:format)                                                                        
users#index              index GET    /index(.:format)                                                                         
users#show                user GET    /users/:id(.:format) 

    <!-- some long code --!>
```                                                                    
いろいろ試してた時に作った名前付きルート`as: :user`が怪しい。
``as: :users``にしてもいいが、後々問題になりそうなので、`resources: users`で対応してみる。

```config/routes.rb

+ resources :users
 
    <!-- some long code --!>

- post "users/:id/update", to: "users#update"
- get "users/:id/edit", to: "users#edit", as: :edit
- post "signup", to: "users#create"
- get "signup", to: "users#new"
- get "index", to: "users#index"
- get "users/:id", to: "users#show", as: :user

    <!-- some long code --!>
```
```
    rails  routes
```
```
    <!-- some long code --!>

users#update                   POST   /users/:id/update(.:format)                                                              
users#edit                edit GET    /users/:id/edit(.:format)                                                                
users#create            signup POST   /signup(.:format)                                                                        
users#new                      GET    /signup(.:format)                                                                        
users#index              index GET    /index(.:format)                                                                         
users#show                     GET    /users/:id(.:format) 

    <!-- some long code --!>
```

#####これでモデルを`@user`にしても、エラーは起きなくなった！
#####また、スコープが`:user`で認識されるようになり、`require(:user)`を加えてのテストも通過し、StrongParametersが適応されたユーザーの新規登録ができるように！

###まとめ
Strong＿Parametersよく分からなかったけど、躓いたことによって、form_withとroutingについても学べたのでよしとする！