Làm thế nào để cho phép một mảng với các tham số mạnh mẽ


269

Tôi có một ứng dụng Rails 3 hoạt động sử dụng has_many: thông qua các liên kết không có, khi tôi làm lại nó dưới dạng ứng dụng Rails 4, cho phép tôi lưu id từ mô hình được liên kết trong phiên bản Rails 4.

Đây là ba mô hình có liên quan giống nhau cho hai phiên bản.

Phân loại.rb

class Categorization < ActiveRecord::Base

  belongs_to :question
  belongs_to :category
end

Câu hỏi

has_many :categorizations
has_many :categories, through: :categorizations

Chuyên mục.rb

has_many :categorizations
has_many :questions, through: :categorizations

Trong cả hai ứng dụng, id danh mục đang được chuyển vào hành động tạo như thế này

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

Trong ứng dụng Rails 3, khi tôi tạo một câu hỏi mới, nó sẽ chèn vào bảng câu hỏi và sau đó vào bảng phân loại

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

Trong ứng dụng rails 4, sau khi nó xử lý các tham số trong Câu hỏi # tạo, tôi gặp lỗi này trong nhật ký máy chủ

Unpermitted parameters: category_ids

và câu hỏi chỉ được đưa vào bảng câu hỏi

 (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

Mặc dù tôi không lưu trữ category_ids trên mô hình Câu hỏi, tôi đặt category_ids làm tham số được phép trong câu hỏi_controll

   def question_params

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

Bất cứ ai cũng có thể giải thích làm thế nào tôi có thể lưu danh mục_ids? Lưu ý, không có hành động tạo nào trong chuyên mục_controll.rb của một trong hai ứng dụng.

Đây là ba bảng giống nhau trong cả hai ứng dụng

 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

Cập nhật

Đây là hành động tạo từ ứng dụng 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

Đây là hành động tạo từ ứng dụng 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

Đây là phương thức 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

Hành động tạo trông như thế nào trong cả hai ứng dụng?
bennick

@bennick Tôi đã thêm hai hành động tạo. Cảm ơn
Leahcim

Câu trả lời:


527

Https://github.com/rails/strong_parameter này có vẻ giống như phần có liên quan của các tài liệu:

Các loại vô hướng được phép là String, Symbol, NilClass, Numeric, TrueClass, falseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch :: Http :: UploadedFile và Rack :: Test :: UploadedFile.

Để khai báo rằng giá trị trong params phải là một mảng các giá trị vô hướng được phép ánh xạ khóa thành một mảng trống:

params.permit(:id => [])

Trong ứng dụng của tôi, category_ids được chuyển đến hành động tạo trong một mảng

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

Do đó, khi khai báo các tham số mạnh, tôi đặt rõ ràng category_ids thành một mảng

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

Hoạt động hoàn hảo ngay bây giờ!

( QUAN TRỌNG: Như @Lenart ghi chú trong các nhận xét, khai báo mảng phải ở cuối danh sách thuộc tính, nếu không bạn sẽ gặp lỗi cú pháp.)


105
Tôi cũng nhận thấy rằng các khai báo cho mảng phải ở cuối danh sách thuộc tính. Nếu không, tôi gặp lỗi cú phápsyntax error, unexpected ')', expecting =>
Lenart

45
Lý do khai báo mảng (tham số lồng nhau) ở cuối là ActionControll :: Paramameter.permit dự kiến ​​mỗi đối số sẽ là Hash hoặc Biểu tượng. Ruby Magic sẽ biến tất cả các cặp giá trị khóa ở cuối cuộc gọi phương thức thành một hàm băm, nhưng Ruby sẽ không biết phải làm gì nếu bạn trộn các ký hiệu với các cặp khóa / giá trị trong lệnh gọi phương thức của bạn.
cùng

7
nếu category_idskhông phải là một mảng (ví dụ: một chuỗi đã được gửi) thì đường ray hoàn toàn bị ERROR TypeError: expected Array (got String) for param `category_ids'hỏng và tăng lên Có phải đó là một lỗi trong đường ray không? Chỉnh sửa: có, đó là: github.com/rails/rails/issues/11502
Dominik Goltermann

4
@Lenart Cảm ơn, tôi nghĩ rằng tôi đang phát điên. Điều này ít nhất sẽ xuất hiện trong strong_params README
Sebastialonso

3
@Lenart bạn có thể thêm nó dưới dạng băm nếu bạn muốn tránh lỗi cú pháp. params.permit(:foo, { bar: [] }, :zoo).
Sở thú Foo Bar

99

Nếu bạn muốn cho phép một mảng băm (hoặc an array of objectstừ phối cảnh của JSON)

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

2 điểm cần chú ý ở đây:

  1. arraynên là đối số cuối cùng của permitphương thức.
  2. bạn nên chỉ định các khóa của hàm băm trong mảng, nếu không bạn sẽ gặp lỗi Unpermitted parameter: array, rất khó để gỡ lỗi trong trường hợp này.

và mảng của mảng không được hỗ trợ (chưa): github.com/rails/rails/issues/23640
Andrei Dziahel

11
arraykhông cần phải ở cuối, nhưng bạn cần chắc chắn rằng bạn có Ruby hợp lệ. params.permit(:foo, array: [:key1, :key2], :bar)sẽ không phải là ruby ​​hợp lệ vì trình thông dịch mong đợi khóa băm: cặp giá trị sau tập đầu tiên. Để có Ruby hợp lệ bạn cầnparams.permit(:foo, {array: [:key1, :key2]}, :bar)
mastaBlasta

Bạn là người Champ!
Lollypop

22

Nó nên như thế

params.permit(:id => [])

Ngoài ra kể từ phiên bản rails 4+, bạn có thể sử dụng:

params.permit(id: [])

12
xin lưu ý rằng mảng không phải là đối số cuối cùng của phương thức cấp phép
Matias Elorriaga

3
Cú pháp băm mà bạn nói áp dụng cho Rails v4 + thực sự là một cú pháp có sẵn trong Ruby 1.9 & mới hơn, không phải khung Rails (mặc dù Rails 4 yêu cầu Ruby 1.9.3 hoặc mới hơn)
MegaTux

11

Nếu bạn có cấu trúc băm như thế này:

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

Sau đó, đây là cách tôi làm cho nó hoạt động:

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

6

Tôi chưa thể nhận xét nhưng theo dõi về giải pháp Fellow Stranger, bạn cũng có thể tiếp tục lồng trong trường hợp bạn có các khóa có giá trị là một mảng. Như thế này:

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

Những công việc này:

params.require(:model).permit(filters: [[:name, values: []]])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.