LoginSignup
1
0

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-01-31

学習メモです。

Strong_Parametersとは?

Rails4.0以降ではコントローラ層で、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で学んだことのまとめです。

解決したい問題その1

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を使いたいのにそれだと意味がない!!

解決したい問題その2

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についても学べたのでよしとする!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0