railsのparams permitすると変更できなくなる

結論から言え!

railsのstrong parameterでpermitしたhashは変更できない

railsのstrong parameter

railsにはstrong parameterと言う機能があります

簡単に説明すると、明示的に許可したparameterのみobjectに渡す仕組みです

railsを書いたことある方なら誰でも一度は使ってるんじゃないでしょうか

下のように主にcontrollerの中で使います

# users_controller.rb

...
...

def show
    @user = user_params
end

...
...

private

def user_params
    params.require(:user).permit(:name, :age)
end

user_paramsメソッドの中でrequireでオブジェクト名を決めてpermitで許可するkey名を指定しています

permitされた値に変更を加えたい

先日、このようにして許可した値に変更を加えたい状況になりました

以下のようにして変更を加えようとしました

# users_controller.rb

...
...

def show
    user_params[:age] += 20 # user_paramsで取得したageに20を加える
    @user = user_params
end

...
...

private

def user_params
    params.require(:user).permit(:name, :age)
end

しかしuser_paramsを表示してみると変更前の値になっていました

permitで返しているのは新しいobject

調べていると下の記事を見つけました

stackoverflow.com

permit returns a new hash with those keys in it, so you're not modifying the real params variable.

permitは許可したkeyを持つ新しいオブジェクトを返すので、元のparameterを変更することはできない

まじか!と思いpermitの定義をみてみると

github.com

 def permit(*filters)
      params = self.class.new
      ...

まじだ!!!

と言うことでparamsを直接変更しようとしてもうまくいきません

諦めて別のhashを作成してそれを渡して解決しました

# users_controller.rb

...
...

def show
 new_params = user_params
    new_params[:age] += 20 # user_paramsから作ったnew_paramsのageに20を加える
    @user = new_params
end

...
...

private

def user_params
    params.require(:user).permit(:name, :age)
end

知らないところで思ってもない処理がされてるもんですね

参考

Strong Parameters in Rails —down the rabbit hole - Tomer Brisker - Medium

Modify ruby hash in place( rails strong params) - Stack Overflow

Modifying strong parameter values after a request | Development Simplified