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.

Eric Chu
  • 1,649
  • 3
  • 20
  • 26

3 Answers3

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
slowjack2k
  • 2,566
  • 1
  • 15
  • 23
  • 1
    (params[:quiz] || {})[:questions].keys – Eric Chu Oct 11 '16 at 22:32
  • 2
    do you think you can explain what that does exactly? its kind of hard to understand – Eric Chu Oct 11 '16 at 22:33
  • See https://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. – gmcnaughton Oct 11 '16 at 22:49
  • See also http://stackoverflow.com/questions/18349887/rails4-how-to-permit-hash-with-dynamic-keys-in-params/34732537 (and other results for "strong parameters permit dynamic") – gmcnaughton Oct 11 '16 at 22:50
8

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

Derek
  • 1,735
  • 17
  • 14
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.

max
  • 96,212
  • 14
  • 104
  • 165