LoginSignup
3
2

More than 1 year has passed since last update.

#Rails の Controller でネストした params を permit / require するのはメソッドチェーンじゃいかんともしがたいからメソッドを何度も実行するしかないのか? ( ActionController::Parameters )

Last updated at Posted at 2020-03-22
  • require / permit / permit! の引数の受け取り方も、返り値も使い方もなんだか不揃いで、なんとも使いがたい
  • メソッドチェーンも使いづらくパラメータがネストされている時に permit / require しづらい
  • permit! は引数を受け取れず、破壊的に params を変えてしまう
  • require と permit を別々に実行して、頑張って組み立て直す必要があるかもしれない
  • 具体ケースとしては JSON リクエストを受け取った結果を Controller の params で扱っているのだが、Rails のもともとのフレームワークのレールからは外れる部分が多いのか、苦労がある。
# ネストした params
params = ActionController::Parameters.new(
  name: 'Alice',
  age: 22,
  contact: ActionController::Parameters.new(
    tel: 07011112222,
    email: 'user@example.com'
  )
)
# => <ActionController::Parameters {"name"=>"Alice", "age"=>22, "contact"=><ActionController::Parameters {"tel"=>941921426, "email"=>"user@example.com"} permitted: false>} permitted: false>


# require は必須パラメータチェックのためだけに利用して、返り値は使わない
params.require([:name, :age, :contact])
params[:contact].require([:tel, :email])

# permit する時はネストの構造に合わせた書き方をして、返り値を permit された params として利用する
peritted_params = params.permit(:name, :age, contact: [:tel, :email])
# => <ActionController::Parameters {"name"=>"Alice", "age"=>22, "contact"=><ActionController::Parameters {"tel"=>941921426, "email"=>"user@example.com"} permitted: true>} permitted: true>

僕はもう疲れたよ

image

公式

  • tap のブロックで頑張る方法が書かれていた
  • 結局 Action Controller Parameters は頼りに出来ない気がした
def person_params
  params.require(:person).permit(:name).tap do |person_params|
    person_params.require(:name) # SAFER
  end
end

ActionController::Parameters

example


# Execute with rails console

# Rails like Nested params with ActionController::Parameters instance
params = ActionController::Parameters.new(
  name: 'Alice',
  age: 22,
  contact: ActionController::Parameters.new(
    tel: 07011112222,
    email: 'user@example.com'
  )
)
# <ActionController::Parameters {"name"=>"Alice", "age"=>22, "contact"=><ActionController::Parameters {"tel"=>941921426, "email"=>"user@example.com"} permitted: false>} permitted: false>

# Ooops
# Args must be Array
params.require(:name, :age, :contact)
# ArgumentError: wrong number of arguments (given 3, expected 1)

# It works
params.require([:name, :age, :contact])
# => ["Alice", 22, <ActionController::Parameters {"tel"=>941921426, "email"=>"user@example.com"} permitted: false>]

# But with method chain
# How to permit multiple params Require and Permit ?

# require method returns values Array
# it is not work for generate permitted params
# because .permit .require both method does not change "params"
params.require([:name, :age, :contact])[2].permit(:tel, :email).require([:tel, :email])
# => [941921426, "user@example.com"]

# require method returns values Array
# Unable to use methods chain
params.require([:name, :age, :contact])[2].require([:tel, :email]).permit(:tel, :email)
# NoMethodError: undefined method `permit' for [941921426, "user@example.com"]:Array

# It is answer?
# User require and permit methods
# Without return values
# Without method chains
# 
# And last execute permit!

params.require([:name, :age, :contact])
params[:contact].require([:tel, :email])

peritted_params = params.permit(:name, :age, contact: [:tel, :email])
# <ActionController::Parameters {"name"=>"Alice", "age"=>22, "contact"=><ActionController::Parameters {"tel"=>941921426, "email"=>"user@example.com"} permitted: true>} permitted: true>

# OR
params.permit(:name, :age, contact: [:tel, :email])
params.permit!
params
# => <ActionController::Parameters {"name"=>"Alice", "age"=>22, "contact"=><ActionController::Parameters {"tel"=>941921426, "email"=>"user@example.com"} permitted: true>} permitted: true>

Original by Github issue

チャットメンバー募集

何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

Twitter

3
2
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
3
2