cómo permitir una matriz con parámetros fuertes

Resuelto Leahcim asked hace 11 años • 6 respuestas

Tengo una aplicación Rails 3 en funcionamiento que usa has_many: a través de asociaciones, lo cual no es así, ya que la rehago como una aplicación Rails 4, lo que me permite guardar identificadores del modelo asociado en la versión Rails 4.

Estos son los tres modelos relevantes y son los mismos para las dos versiones.

Categorización.rb

class Categorization < ActiveRecord::Base

  belongs_to :question
  belongs_to :category
end

Pregunta.rb

has_many :categorizations
has_many :categories, through: :categorizations

Categoría.rb

has_many :categorizations
has_many :questions, through: :categorizations

En ambas aplicaciones, los identificadores de categoría se pasan a la acción de creación como esta

  "question"=>{"question_content"=>"How do you spell car?", "question_details"=>"blah ", "category_ids"=>["", "2"],

En la aplicación Rails 3, cuando creo una nueva pregunta, se inserta en la tabla de preguntas y luego en la tabla de categorizaciones.

 SQL (82.1ms)  INSERT INTO "questions" ("accepted_answer_id", "city", "created_at", "details", "province", "province_id", "question", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)  [["accepted_answer_id", nil], ["city", "dd"], ["created_at", Tue, 14 May 2013 17:10:25 UTC +00:00], ["details", "greyound?"], ["province", nil], ["province_id", 2], ["question", "Whos' the biggest dog in the world"], ["updated_at", Tue, 14 May 2013 17:10:25 UTC +00:00], ["user_id", 53]]
  SQL (0.4ms)  INSERT INTO "categorizations" ("category_id", "created_at", "question_id", "updated_at") VALUES (?, ?, ?, ?)  [["category_id", 2], ["created_at", Tue, 14 May 2013 17:10:25 UTC +00:00], ["question_id", 66], ["updated_at", Tue, 14 May 2013 17:10:25 UTC +00:00]]

En la aplicación Rails 4, después de procesar los parámetros en QuestionController#create, aparece este error en los registros del servidor.

Unpermitted parameters: category_ids

y la pregunta solo se inserta en la tabla de preguntas

 (0.2ms)  BEGIN
  SQL (67.6ms)  INSERT INTO "questions" ("city", "created_at", "province_id", "question_content", "question_details", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["city", "dd"], ["created_at", Tue, 14 May 2013 17:17:53 UTC +00:00], ["province_id", 3], ["question_content", "How's your car?"], ["question_details", "is it runnign"], ["updated_at", Tue, 14 May 2013 17:17:53 UTC +00:00], ["user_id", 12]]
   (31.9ms)  COMMIT

Aunque no estoy almacenando los Category_ids en el modelo de Preguntas, configuro Category_ids como un parámetro permitido en el questions_controller.

   def question_params

      params.require(:question).permit(:question_details, :question_content, :user_id, :accepted_answer_id, :province_id, :city, :category_ids)
    end

¿Alguien puede explicar cómo se supone que debo guardar los Category_IDs? Tenga en cuenta que no hay ninguna acción de creación en categorías_controller.rb de ninguna de las aplicaciones.

Estas son las tres tablas que son iguales en ambas apps

 create_table "questions", force: true do |t|
    t.text     "question_details"
    t.string   "question_content"
    t.integer  "user_id"
    t.integer  "accepted_answer_id"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "province_id"
    t.string   "city"
  end

 create_table "categories", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "categorizations", force: true do |t|
    t.integer  "category_id"
    t.integer  "question_id"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

Actualizar

Esta es la acción de creación desde la aplicación Rails 3.

  def create
      @question = Question.new(params[:question])
      respond_to do |format|
      if @question.save
        format.html { redirect_to @question, notice: 'Question was successfully created.' }
        format.json { render json: @question, status: :created, location: @question }
      else
        format.html { render action: "new" }
        format.json { render json: @question.errors, status: :unprocessable_entity }
      end
    end
end

Esta es la acción de creación desde la aplicación Rails 4.

   def create
      @question = Question.new(question_params)

       respond_to do |format|
      if @question.save
        format.html { redirect_to @question, notice: 'Question was successfully created.' }
        format.json { render json: @question, status: :created, location: @question }
      else
        format.html { render action: "new" }
        format.json { render json: @question.errors, status: :unprocessable_entity }
      end
    end
    end

Este es el método question_params

 private
    def question_params 
      params.require(:question).permit(:question_details, :question_content, :user_id, :accepted_answer_id, :province_id, :city, :category_ids)
    end
Leahcim avatar May 15 '13 00:05 Leahcim
Aceptado

Este https://github.com/rails/strong_parameters parece la sección relevante de los documentos:

Los tipos escalares permitidos son String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile y Rack::Test::UploadedFile.

Para declarar que el valor en params debe ser una matriz de valores escalares permitidos, asigne la clave a una matriz vacía:

params.permit(:id => [])

En mi aplicación, los Category_ids se pasan a la acción de creación en una matriz.

"category_ids"=>["", "2"],

Por lo tanto, al declarar parámetros fuertes, configuro explícitamente categoría_ids para que sea una matriz

params.require(:question).permit(:question_details, :question_content, :user_id, :accepted_answer_id, :province_id, :city, :category_ids => [])

¡Funciona perfectamente ahora!

( IMPORTANTE: como señala @Lenart en los comentarios, las declaraciones de matriz deben estar al final de la lista de atributos; de lo contrario, obtendrá un error de sintaxis).

Leahcim avatar May 15 '2013 02:05 Leahcim

Si desea permitir una serie de hashes (o an array of objectsdesde la perspectiva de JSON)

params.permit(:foo, array: [:key1, :key2])

2 puntos a tener en cuenta aquí:

  1. arraydebería ser el último argumento del permitmétodo.
  2. debe especificar las claves del hash en la matriz; de lo contrario, obtendrá un error Unpermitted parameter: array, que es muy difícil de depurar en este caso.
Brian avatar May 17 '2015 09:05 Brian

La matriz debe ser el último argumento del método de permiso.

params.permit(:id => [])

Además, desde Ruby 1.9 o posterior, puedes usar:

params.permit(id: [])
Matias Seguel avatar Jul 06 '2017 14:07 Matias Seguel

Si tiene una estructura hash como esta:

Parameters: {"link"=>{"title"=>"Something", "time_span"=>[{"start"=>"2017-05-06T16:00:00.000Z", "end"=>"2017-05-06T17:00:00.000Z"}]}}

Entonces así es como lo hice funcionar:

params.require(:link).permit(:title, time_span: [[:start, :end]])
Fellow Stranger avatar May 03 '2017 15:05 Fellow Stranger

cuando desee permitir múltiples campos de matriz, tendrá que enumerar los campos de matriz al final mientras lo permite, como se indica:

params.require(:questions).permit(:question, :user_id, answers: [], selected_answer: [] )

(esto funciona)

Dev Bhatt avatar Feb 17 '2021 08:02 Dev Bhatt