cara mengizinkan array dengan parameter kuat

269

Saya memiliki aplikasi Rails 3 yang berfungsi yang menggunakan has_many: melalui asosiasi yang tidak, karena saya membuat kembali sebagai aplikasi Rails 4, memungkinkan saya menyimpan id dari model terkait dalam versi Rails 4.

Ini adalah tiga model yang relevan sama untuk kedua versi.

Kategorisasi.rb

class Categorization < ActiveRecord::Base

  belongs_to :question
  belongs_to :category
end

Pertanyaan.rb

has_many :categorizations
has_many :categories, through: :categorizations

Category.rb

has_many :categorizations
has_many :questions, through: :categorizations

Di kedua aplikasi, id kategori diteruskan ke tindakan pembuatan seperti ini

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

Di aplikasi Rails 3, ketika saya membuat pertanyaan baru, itu memasukkan tabel pertanyaan dan kemudian ke tabel kategorisasi

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

Di app rails 4, setelah memproses parameter di QuestionController # create, saya mendapatkan error ini di log server

Unpermitted parameters: category_ids

dan pertanyaan hanya dimasukkan ke dalam tabel pertanyaan

 (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

Meskipun saya tidak menyimpan category_ids pada model Pertanyaan, saya menetapkan category_ids sebagai parameter yang diizinkan dalam question_controller

   def question_params

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

Adakah yang bisa menjelaskan bagaimana saya seharusnya menyimpan category_ids? Catatan, tidak ada tindakan buat di category_controller.rb dari salah satu aplikasi.

Ini adalah tiga tabel yang sama di kedua aplikasi

 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

Memperbarui

Ini adalah aksi buat dari aplikasi 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

Ini adalah aksi buat dari aplikasi 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

Ini adalah metode 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
sumber
Seperti apakah tampilan tindakan di kedua aplikasi?
bennick
@Bennick Saya menambahkan dua tindakan buat. Terima kasih
Leahcim

Jawaban:

527

Https://github.com/rails/strong_parameters ini sepertinya bagian yang relevan dari dokumen:

Jenis skalar yang diizinkan adalah String, Simbol, NilClass, Numeric, TrueClass, FalseClass, Tanggal, Waktu, DateTime, StringIO, IO, ActionDispatch :: Http :: UploadedFile dan Rack :: Test :: UploadedFile.

Untuk menyatakan bahwa nilai dalam params harus berupa array nilai skalar yang diijinkan memetakan kunci ke array kosong:

params.permit(:id => [])

Di aplikasi saya, category_ids diteruskan ke tindakan buat dalam array

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

Oleh karena itu, ketika mendeklarasikan parameter kuat, saya secara eksplisit mengatur category_ids menjadi array

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

Bekerja dengan baik sekarang!

( PENTING: Seperti yang dicatat @Lenart di komentar, deklarasi array harus di akhir daftar atribut, jika tidak Anda akan mendapatkan kesalahan sintaks.)

Leahcim
sumber
105
Saya juga memperhatikan bahwa deklarasi untuk array harus ada di akhir daftar atribut. Kalau tidak, saya mendapatkan kesalahan sintakssyntax error, unexpected ')', expecting =>
Lenart
45
Deklarasi array alasan (nested params) pada akhirnya adalah bahwa ActionController :: Parameters.permit mengharapkan setiap argumen menjadi Hash atau Simbol. Ruby magic akan mengubah semua pasangan nilai kunci di akhir pemanggilan metode menjadi satu hash, tetapi Ruby tidak akan tahu apa yang harus dilakukan jika Anda mencampur simbol dengan pasangan kunci / nilai dalam pemanggilan metode Anda.
sama
7
jika category_idsbukan array (mis. string dikirim) maka rail benar-benar menjadi gila dan menimbulkan a ERROR TypeError: expected Array (got String) for param `category_ids'Apakah itu bug di rails? Sunting: ya itu adalah: github.com/rails/rails/issues/11502
Dominik Goltermann
4
@Lenart Terima kasih, saya pikir saya sudah gila. Paling tidak ini akan muncul di strong_params README
Sebastialonso
3
@Lenart Anda dapat menambahkannya sebagai hash jika Anda ingin menghindari kesalahan sintaksis. params.permit(:foo, { bar: [] }, :zoo).
Foo Bar Zoo
99

Jika Anda ingin mengizinkan array hash (atau an array of objectsdari perspektif JSON)

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

2 poin untuk diperhatikan di sini:

  1. arrayharus menjadi argumen terakhir dari permitmetode ini.
  2. Anda harus menentukan kunci hash dalam array, jika tidak Anda akan mendapatkan kesalahan Unpermitted parameter: array, yang sangat sulit untuk di-debug dalam kasus ini.
Brian
sumber
dan array array belum didukung (belum): github.com/rails/rails/issues/23640
Andrei Dziahel
11
arraytidak harus pada akhirnya, tetapi Anda harus memastikan bahwa Anda memiliki Ruby yang valid. params.permit(:foo, array: [:key1, :key2], :bar)tidak akan menjadi ruby ​​yang valid karena juru bahasa mengharapkan kunci hash: pasangan nilai setelah set pertama. Untuk memiliki Ruby yang valid, Anda perluparams.permit(:foo, {array: [:key1, :key2]}, :bar)
mastaBlasta
Anda adalah seorang Champ!
Lollypop
22

Itu harus seperti

params.permit(:id => [])

Juga karena rails versi 4+ Anda dapat menggunakan:

params.permit(id: [])
Matias Seguel
sumber
12
tolong jangan bahwa array harus menjadi argumen terakhir dari metode perizinan
Matias Elorriaga
3
Sintaks hash yang Anda katakan berlaku untuk Rails v4 + sebenarnya adalah sintaks yang tersedia di Ruby 1.9 & yang lebih baru, bukan kerangka Rails (meskipun Rails 4 membutuhkan Ruby 1.9.3 atau yang lebih baru)
MegaTux
11

Jika Anda memiliki struktur hash seperti ini:

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

Maka beginilah cara saya membuatnya bekerja:

params.require(:link).permit(:title, time_span: [[:start, :end]])
Sesama Asing
sumber
6

Saya belum bisa berkomentar tetapi mengikuti solusi Fellow Stranger Anda juga dapat tetap bersarang jika Anda memiliki kunci yang nilainya array. Seperti ini:

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

Ini bekerja:

params.require(:model).permit(filters: [[:name, values: []]])
Daniel Duque
sumber