How to permit hash with * key => values?
Asked Answered
C

4

5

I want to create an object with strong params that can accept dynamic hash keys.

This is my code,

Quiz.create(quiz_params)


def quiz_params
  params.require(:quiz).permit(:user_id, :percent, :grade, questions: {})
end

data that gets passed in would look something like this.

// the keys that get passed into question is always different

quiz: {
  user_id: 1,
  percent: 80,
  grade: "B",
  questions: {
    "12": "24",
    "1": "12",
    "4": "3",
    "5": "22"
  }
}

Currently however, when I try to create a Quiz, the questions hash turns out empty.

Conform answered 11/10, 2016 at 21:24 Comment(0)
L
9

Until now I have only seen this:

def quiz_params
  questions_params = (params[:quiz] || {})[:questions].keys
  params.require(:quiz).permit(:user_id, :percent, :grade, questions: questions_params)
end
Limousine answered 11/10, 2016 at 21:28 Comment(4)
(params[:quiz] || {})[:questions].keysConform
do you think you can explain what that does exactly? its kind of hard to understandConform
See github.com/rails/rails/issues/9454 -- unfortunately there is no easy way to say "permit this key to contain anything". @slowjack2k's answer does it manually: literally, you permit the :questions key to contain a specific list of keys, which you get by asking it for every key it has. This will work for your example case, but unfortunately won't allow arbitrary nesting.Amelia
See also #18350387 (and other results for "strong parameters permit dynamic")Amelia
P
9

In rails 5.1.2, the original syntax of passing an empty hash for questions should work:

def quiz_params
  params.require(:quiz).permit(:user_id, :percent, :grade, questions: {})
end

See https://github.com/rails/rails/commit/e86524c0c5a26ceec92895c830d1355ae47a7034

Pisa answered 3/7, 2017 at 17:34 Comment(0)
B
0

Have you considered changing your api instead?

quiz: {
  user_id: 1,
  percent: 80,
  grade: "B",
  answers_attributes: [
    {
      question_id: "12"
      value: "24"
    }, 
    {
      question_id: "3"
      value: "12"
    }
    # ...
  ]
}

This is how both form_for and nested_attributes work. Instead of giving yourself a potential mass injection vulnerability - rethink your domain modeling. You can do better.

Bibulous answered 12/10, 2016 at 1:9 Comment(1)
Wow, thanks! I didn't think about this. I'm still learning :PConform
N
0

Following way you can add new key/value in the strong parameter

class UserController < ApplicationController
  def create
    user_params[:department] = Department.find(params[:department_id]).name
    user = User.new(user_params)

    if user.save
      # success
    else
      # failure
    end
  end

  private

  def user_params
    @_user_params ||= params.require(:user).permit(:name, :department_id)
  end
end
Nordrheinwestfalen answered 20/3 at 10:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.