ruby-on-rails - rails - strong parameters nested attributes
Cómo permitir una matriz con parámetros fuertes. (5)
Debería ser como
params.permit(:id => [])
También desde la versión 4+ de rieles puedes usar:
params.permit(id: [])
Tengo una aplicación de Rails 3 que funciona y usa has_many: a través de asociaciones que no lo es, ya que la rehago como una aplicación de Rails 4, lo que me permite guardar los identificadores del modelo asociado en la versión de Rails 4.
Estos son los tres modelos relevantes que son los mismos para las dos versiones.
Categorización.rb
class Categorization < ActiveRecord::Base
belongs_to :question
belongs_to :category
end
Question.rb
has_many :categorizations
has_many :categories, through: :categorizations
Category.rb
has_many :categorizations
has_many :questions, through: :categorizations
En ambas aplicaciones, los identificadores de categoría se pasan a la acción crear 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 está insertando 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 las 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 las category_ids? Tenga en cuenta que no hay ninguna acción de creación en el categories_controller.rb de ninguna de las aplicaciones.
Estas son las tres tablas que son iguales en ambas aplicaciones.
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 crear 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 crear 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
Este https://github.com/rails/strong_parameters parece la sección relevante de los documentos:
Los tipos de escalar 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 crear en una matriz
"category_ids"=>["", "2"],
Por lo tanto, cuando declaro parámetros fuertes, explícitamente establezco category_ids como una matriz
params.require(:question).permit(:question_details, :question_content, :user_id, :accepted_answer_id, :province_id, :city, :category_ids => [])
¡Funciona perfectamente ahora!
No puedo comentar todavía, pero siguiendo la solución de Fellow Stranger, también puede seguir anidando en caso de que tenga claves cuyos valores son una matriz. Me gusta esto:
filters: [{ name: ''test name'', values: [''test value 1'', ''test value 2''] }]
Esto funciona:
params.require(:model).permit(filters: [[:name, values: []]])
Si desea permitir una matriz de hashes (o an array of objects
desde la perspectiva de JSON)
params.permit(:foo, array: [:key1, :key2])
2 puntos a notar aquí:
-
array
debe ser el último argumento del método depermit
. - 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.
Si tienes 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]])