LoginSignup
0
3

More than 3 years have passed since last update.

【学習メモ】Strong Parameters と accepts_nested_attributes_for

Last updated at Posted at 2020-06-17

目次

1.背景
2.Strong Parametersについておさらい
3.モデルに、accepts_nested_attributes_forを使っている場合
4.参考

1.背景

Railsでオリジナルアプリを開発しているが、「Unpermitted parameter: :_destroy」という表示が出てしまい、それをRailsガイドを確認しながら解決させたので、その学びをアウトプットするため、記載する。

2.Strong Parametersについておさらい

Railsガイドの説明によると、Strong Parametersとは、

strong parametersを用いることで、Action Controllerのパラメータが許可されるまでActive Modelの「マスアサインメント」に利用されることを禁止できます。つまり、多くの属性を一度に更新したい場合は、どの属性のマスアップデートを許可するかを開発者が明示的に指定しなければなりません。大雑把にすべての属性の更新を一括で許可してしまうと、外部に公開する必要のない属性まで誤って公開してしまう可能性が生じるため、そのような事態を防ぐための機能です。

さらに、パラメータの属性に「必須 (required)」を指定することで、事前に定義したraise/rescueフローによって、渡された必須パラメータが不足している場合に「400 Bad Request」で終了させることもできます。

そして、Controllerの例について、こちらもRailsガイドの例を参照。

controller.rb
class PeopleController < ActionController::Base
  # 以下のコードはActiveModel::ForbiddenAttributesError例外を発生します
  # 明示的な許可を行なわずに、パラメータを一括で渡してしまう
  # 危険な「マスアサインメント」が行われているからです。
  def create
    Person.create(params[:person])
  end

  # 以下のコードは、パラメータにpersonキーがあれば成功します。
  # personキーがない場合は
  # ActionController::ParameterMissing例外を発生します。
  # この例外はActionController::Baseにキャッチされ、
  # 400 Bad Requestを返します。
  def update
    person = current_account.people.find(params[:id])
    person.update!(person_params)
    redirect_to person
  end

  private
    # 許可するパラメータはprivateメソッドでカプセル化します。
    # これは非常によい手法であり、createとupdateの両方で使いまわすことで
    # 同じ許可を与えることができます。また、許可する属性をユーザーごとにチェックするよう
    # このメソッドを特殊化することもできます。
    def person_params
      params.require(:person).permit(:name, :age)
    end
end

3.モデルに、accepts_nested_attributes_forを使っている場合

accepts_nested_attributes_for(クラスメソッド)を使っている場合、下記のように記述することで、Relation関係にあるレコードの更新・削除が可能。このメソッドは、id_destroyパラメータに基づいて動作する。

<Railsガイドの事例>

controller.rb
params.permit(:name, { emails: [] },
              friends: [ :name,
                         { family: [ :name ], hobbies: [] }])

<私のオリジナルアプリ開発の事例>

controller.rb
[省略]
  def create
    @record = Record.new(record_params)
    if @record.save
      flash[:success] = "練習内容の登録が完了しました。"
      redirect_to records_url
    else
      flash[:alert] = "登録に失敗しました。"
      render :new
    end
  end

[省略]

  def record_params
    params.require(:record).permit(:record_id, :training_date, :learning_point, outputs_attributes:[:output_name, :id, :_destroy], practices_attributes:[:practice_item, :practice_time, :id, :_destroy], tasks_attributes:[:task_name, :id, :_destroy]).merge(user_id: current_user.id)
  end

子テーブルにある属性を、

params.require(:model).permit(:models_attributes:[:id,:arg, :arg2, :_destroy]

の形でまとめると実装できる。
※モデルに「has_many」「belongs_to」を忘れないこと

4.参考

Railsガイド Strong Parameters

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