come consentire un array con parametri forti


269

Ho un'app Rails 3 funzionante che usa has_many: tramite associazioni che non lo sono, poiché la rifaccio come app Rails 4, permettendomi di salvare gli ID dal modello associato nella versione di Rails 4.

Questi sono i tre modelli rilevanti sono gli stessi per le due versioni.

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

In entrambe le app, gli ID categoria vengono passati all'azione di creazione in questo modo

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

Nell'app Rails 3, quando creo una nuova domanda, questa viene inserita nella tabella delle domande e quindi nella tabella delle categorizzazioni

 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]]

Nell'app rails 4, dopo aver elaborato i parametri in QuestionController # create, visualizzo questo errore nei registri del server

Unpermitted parameters: category_ids

e la domanda viene solo inserita nella tabella delle domande

 (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

Anche se non sto memorizzando category_ids sul modello Domande, ho impostato category_ids come parametro consentito nel question_controller

   def question_params

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

Qualcuno può spiegare come dovrei salvare i category_ids? Nota, non esiste alcuna azione di creazione nel categorie_controller.rb di entrambe le app.

Queste sono le tre tabelle che sono uguali in entrambe le app

 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

Aggiornare

Questa è l'azione di creazione dall'app 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

Questa è l'azione di creazione dall'app 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

Questo è il metodo 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

Come si presenta l'azione di creazione in entrambe le app?
bennick

@bennick Ho aggiunto le due azioni create. Grazie
Leahcim,

Risposte:


527

Questo https://github.com/rails/strong_parameters sembra la sezione pertinente della documentazione:

I tipi scalari consentiti sono String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch :: Http :: UploadedFile e Rack :: Test :: UploadedFile.

Per dichiarare che il valore in params deve essere un array di valori scalari consentiti, mappare la chiave su un array vuoto:

params.permit(:id => [])

Nella mia app, i category_ids vengono passati all'azione create in un array

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

Pertanto, nel dichiarare parametri forti, ho impostato esplicitamente category_ids come array

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

Funziona perfettamente ora!

( IMPORTANTE: come nota @Lenart nei commenti, le dichiarazioni di array devono trovarsi alla fine dell'elenco degli attributi, altrimenti verrà visualizzato un errore di sintassi.)


105
Ho anche notato che le dichiarazioni per gli array dovrebbero essere alla fine dell'elenco degli attributi. Altrimenti ricevo un errore di sintassisyntax error, unexpected ')', expecting =>
Lenart il

45
Il motivo per cui le dichiarazioni di array (parametri nidificati) sono alla fine è che ActionController :: Parameters.permit si aspetta che ogni argomento sia un hash o un simbolo. La magia di Ruby trasformerà tutte le coppie di valori-chiave s alla fine di una chiamata di metodo in un hash, ma Ruby non saprà cosa fare se mescoli simboli con coppie chiave / valore nella tua chiamata di metodo.
stessi

7
se category_idsnon è un array (ad es. è stata inviata una stringa), le rotaie vanno completamente pazze e generano a ERROR TypeError: expected Array (got String) for param `category_ids'È un bug nelle rotaie? Modifica: sì, lo è: github.com/rails/rails/issues/11502
Dominik Goltermann,

4
@Lenart Grazie, pensavo di impazzire. Questo dovrebbe almeno apparire nel README strong_params
Sebastialonso

3
@Lenart puoi aggiungerlo come hash se vuoi evitare errori di sintassi. params.permit(:foo, { bar: [] }, :zoo).
Foo Bar Zoo,

99

Se si desidera consentire una matrice di hash (o an array of objectsdalla prospettiva di JSON)

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

2 punti da notare qui:

  1. arraydovrebbe essere l'ultimo argomento del permitmetodo.
  2. dovresti specificare le chiavi dell'hash nell'array, altrimenti otterrai un errore Unpermitted parameter: array, che in questo caso è molto difficile eseguire il debug.

e le matrici di matrici non sono supportate (ancora): github.com/rails/rails/issues/23640
Andrei Dziahel

11
arraynon deve essere alla fine, ma devi assicurarti di avere Ruby valido. params.permit(:foo, array: [:key1, :key2], :bar)non sarebbe un rubino valido poiché l'interprete si aspetta chiave hash: coppie di valori dopo il primo set. Per avere Ruby valido è necessarioparams.permit(:foo, {array: [:key1, :key2]}, :bar)
mastaBlasta,

Sei un campione!
Lollypop,

22

Dovrebbe essere come

params.permit(:id => [])

Inoltre dalla versione 4+ di rails puoi usare:

params.permit(id: [])

12
per favore, non che l'array dovrebbe essere l'ultimo argomento del metodo di autorizzazione
Matias Elorriaga,

3
Quella sintassi hash che hai detto applicare per Rails v4 + è in realtà una sintassi disponibile in Ruby 1.9 e versioni successive, non nel framework Rails (anche se Rails 4 richiede Ruby 1.9.3 o
versioni

11

Se hai una struttura di hash come questa:

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

Quindi è così che l'ho fatto funzionare:

params.require(:link).permit(:title, time_span: [[:start, :end]])

6

Non posso ancora commentare, ma seguendo la soluzione Fellow Stranger puoi anche continuare a nidificare nel caso in cui tu abbia chiavi i cui valori sono un array. Come questo:

filters: [{ name: 'test name', values: ['test value 1', 'test value 2'] }]

Questo funziona:

params.require(:model).permit(filters: [[:name, values: []]])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.