Eu tenho um aplicativo Rails 3 em funcionamento que usa has_many: por meio de associações que não são, pois eu o refizo como um aplicativo Rails 4, permitindo salvar IDs do modelo associado na versão Rails 4.
Estes são os três modelos relevantes são os mesmos para as duas versões.
Categorization.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
Nos dois aplicativos, os IDs da categoria são passados para a ação de criação como esta
"question"=>{"question_content"=>"How do you spell car?", "question_details"=>"blah ", "category_ids"=>["", "2"],
No aplicativo Rails 3, quando crio uma nova pergunta, ele é inserido na tabela de perguntas e depois na tabela de categorizações
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]]
No aplicativo rails 4, depois de processar os parâmetros no QuestionController # create, estou recebendo esse erro nos logs do servidor
Unpermitted parameters: category_ids
e a pergunta está sendo inserida apenas na tabela de perguntas
(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
Embora eu não esteja armazenando os category_ids no modelo de Perguntas, defino category_ids como um parâmetro permitido no questions_controller
def question_params
params.require(:question).permit(:question_details, :question_content, :user_id, :accepted_answer_id, :province_id, :city, :category_ids)
end
Alguém pode explicar como eu devo salvar os category_ids? Observe que não há ação de criação no categories_controller.rb de qualquer aplicativo.
Estas são as três tabelas iguais nos dois aplicativos
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
Atualizar
Esta é a ação de criação do aplicativo 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 é a ação de criação do aplicativo 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 é o 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
fonte
Respostas:
Este https://github.com/rails/strong_parameters parece a seção relevante dos documentos:
No meu aplicativo, os category_ids são passados para a ação create em uma matriz
Portanto, ao declarar parâmetros fortes, eu defino explicitamente category_ids como uma matriz
Funciona perfeitamente agora!
( IMPORTANTE: Como o @Lenart observa nos comentários, as declarações da matriz devem estar no final da lista de atributos; caso contrário, você receberá um erro de sintaxe.)
fonte
syntax error, unexpected ')', expecting =>
category_ids
não for um array (por exemplo, uma string foi enviada), os trilhos ficam totalmente loucos e aumentam aERROR TypeError: expected Array (got String) for param `category_ids'
Isso é um bug nos trilhos? Edit: yes is: github.com/rails/rails/issues/11502params.permit(:foo, { bar: [] }, :zoo)
.Se você deseja permitir uma matriz de hashes (ou
an array of objects
da perspectiva do JSON)2 pontos a serem observados aqui:
array
deve ser o último argumento dopermit
métodoUnpermitted parameter: array
, o que é muito difícil de depurar nesse caso.fonte
array
não precisa estar no final, mas você precisa ter o Ruby válido.params.permit(:foo, array: [:key1, :key2], :bar)
não seria válido ruby, pois o intérprete espera pares de chave de hash: valor após o primeiro conjunto. Para ter validade Ruby que você precisaparams.permit(:foo, {array: [:key1, :key2]}, :bar)
Deveria ser como
Além disso, desde a versão 4+ do Rails, você pode usar:
fonte
Se você tem uma estrutura de hash como esta:
Então é assim que eu consegui funcionar:
fonte
Ainda não posso comentar, mas, seguindo a solução Fellow Stranger, você também pode continuar aninhando caso tenha chaves cujos valores são uma matriz. Como isso:
Isso funciona:
fonte