Skip to content

Instantly share code, notes, and snippets.

@soma-git-practice
Last active November 18, 2024 23:50
Show Gist options
  • Save soma-git-practice/31a9da804beaf40eb87f907d18515a6b to your computer and use it in GitHub Desktop.
Save soma-git-practice/31a9da804beaf40eb87f907d18515a6b to your computer and use it in GitHub Desktop.
deviseのparameter_sanitizer.rbを読むメモ

ビューから渡ってきた値をHoge::RegistrationsControllerで加工しようとした。 覚えてなくて再現もできないが、パラメータを再代入できなかったり、unpermitted paramterとなった。 ストロングパラメータ周りのコードを読めば何かわかるかもと思いコードを読んでみることにした。

テスト動かす

bin/test test/parameter_sanitizer_test.rb

devise/parameter_sanitizerは、ActionController::Parametersのラッパークラスってやつ?

test/parameter_sanitizer_test.rb:70~75を追いかけた。

# 70
sanitizer = begin
  params = ActionController::Parameters.new('user' => { 'username' => 'jose' })
  Devise::ParameterSanitizer.new(User, :user, params)
end

#71
sanitizer.permit(:sign_in) do |user|
  user.permit(:username)
end
# sanitizer.instance_variable_get(:@permitted)[:sign_in] # => #<Proc:~~~devise/test/parameter_sanitizer_test.rb:71>

#75
sanitized = sanitizer.sanitize(:sign_in)
#lib/devise/parameter_sanitizer.rb:70#sanitize
#    permissions = #<Proc:~~~devise/test/parameter_sanitizer_test.rb:71>
#lib/devise/parameter_sanitizer.rb:74
#    cast_to_hash permissions.call(default_params)
#    ->(user){user.permit(:username)}.call(#<ActionController::Parameters {"username"=>"jose"} permitted: false>)
#        #<ActionController::Parameters {"username"=>"jose"} permitted: false>.permit(:user_name)

分かったことは、 Devise::ParameterSanitizerのインスタンスメソッドpermitに渡すブロックは、
Devise::ParameterSanitizerの初期化で渡した、
ActionController::Parametersインスタンスに対して実行されること。

動作確認していないが、以下のコードでコントローラ内で再代入できるんじゃないだろうか!?!?

sanitizer = begin
  params = ActionController::Parameters.new('user' => { 'username' => 'jose' })
  Devise::ParameterSanitizer.new(User, :user, params)
end
sanitizer.permit(:sign_in) do |params|
  params['gender'] = params['username'] == 'jose' ? 'man' : 'woman'
  params.permit(:username, :gender)
end

Devise::ParameterSanitizer#sanitizeは、<#ActionController::Parameters ~~ permitted: true >.to_hの結果を返すメソッド。 Devise::ParameterSanitizer#permitは、<#Devise::ParameterSanitizer @permitted={}>のpermitted[action]に値を追加するメソッド。

test/controllers/custom_registrations_controller_test.rbtest/rails_app/app/controllers/custom/registrations_controller.rbapp/controllers/devise/registrations_controller.rbを改造すれば動作確認できそうだ。

actionpack/lib/action_controller/metal/strong_parameters.rbを読む。

actionpack/test/controller/parameters/parameters_permit_test.rbactionpack/test/controller/required_params_test.rbを使って読むと良さそうな感じする。

actionpack/test/controller/parametersはパラメータ詰まってそう。

railsのテストコードってどうやって動かすんだろ?絶対これだ。

  1. actionpack/bin/test
  2. tools/README.md
  3. tools/test.rb

ポイントをメモった

  • COMPONENT_ROOTは、"rails/actionpack"にする
  • "rails/tools/test.rb"をロードする
  • $: << rails/actionpack/test
  • require "bundler/setup"理解してないけどGemfileに書かれたジェムへのパスを$:に追加してるんじゃないか?今度調べる。
  • それ以外はテスト関連の準備してるんだな。詳しくしらべなくて良さそう。

コード量少ないからこっちから先読む。actionpack/test/controller/required_params_test.rb

bundle install
cd actionpack
bin/test test/controller/required_params_test.rb

わーい、動いた

  • actionpack/test/controller/required_params_test.rb:3
  • actionpack/test/abstract_unit.rb:3 # ==> actionpack/libを$:に追加
  • actionpack/test/abstract_unit.rb:19 # => actionpack/lib/action_controller.rbをロード

railsのコードを読むのは難しいな。。。。

分かったこと

  • permit(:存在しないキー) # => ActionController::UnpermittedParameters: found unpermitted parameters
  • <ActioinController::Parameters pertmited:falese>.to_h # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment