Các thuộc tính lồng nhau không tham số


127

Tôi có một Billđối tượng, trong đó có nhiều Dueđối tượng. Đối Duetượng cũng thuộc về a Person. Tôi muốn một hình thức có thể tạo tất cả Billvà con của nó Duestrong một trang. Tôi đang cố gắng tạo một biểu mẫu bằng cách sử dụng các thuộc tính lồng nhau, tương tự như các thuộc tính trong Railscast này .

Mã liên quan được liệt kê dưới đây:

do.rb

class Due < ActiveRecord::Base
    belongs_to :person
    belongs_to :bill
end

hóa đơn

class Bill < ActiveRecord::Base
    has_many :dues, :dependent => :destroy 
    accepts_nested_attributes_for :dues, :allow_destroy => true
end

bill_controll.rb

  # GET /bills/new
  def new
      @bill = Bill.new
      3.times { @bill.dues.build }
  end

hóa đơn / _form.html.erb

  <%= form_for(@bill) do |f| %>
    <div class="field">
        <%= f.label :company %><br />
        <%= f.text_field :company %>
    </div>
    <div class="field">
        <%= f.label :month %><br />
        <%= f.text_field :month %>
    </div>
    <div class="field">
        <%= f.label :year %><br />
        <%= f.number_field :year %>
    </div>
    <div class="actions">
        <%= f.submit %>
    </div>
    <%= f.fields_for :dues do |builder| %>
        <%= render 'due_fields', :f => builder %>
    <% end %>
  <% end %>

hóa đơn / _due_fields.html.erb

<div>
    <%= f.label :amount, "Amount" %>        
    <%= f.text_field :amount %>
    <br>
    <%= f.label :person_id, "Renter" %>
    <%= f.text_field :person_id %>
</div>

CẬP NHẬT để bill_controll.rb Điều này hoạt động!

def bill_params 
  params
  .require(:bill)
  .permit(:company, :month, :year, dues_attributes: [:amount, :person_id]) 
end

Các trường thích hợp được hiển thị trên trang (mặc dù chưa có danh sách thả xuống Person) và gửi thành công. Tuy nhiên, không có khoản phí con nào được lưu vào cơ sở dữ liệu và một lỗi được đưa vào nhật ký máy chủ:

Unpermitted parameters: dues_attributes

Ngay trước khi xảy ra lỗi, nhật ký sẽ hiển thị điều này:

Started POST "/bills" for 127.0.0.1 at 2013-04-10 00:16:37 -0700
Processing by BillsController#create as HTML<br>
Parameters: {"utf8"=>"✓", 
"authenticity_token"=>"ipxBOLOjx68fwvfmsMG3FecV/q/hPqUHsluBCPN2BeU=",
 "bill"=>{"company"=>"Comcast", "month"=>"April ", 
"year"=>"2013", "dues_attributes"=>{
"0"=>{"amount"=>"30", "person_id"=>"1"}, 
"1"=>{"amount"=>"30", "person_id"=>"2"},
 "2"=>{"amount"=>"30", "person_id"=>"3"}}}, "commit"=>"Create Bill"}

Đã có một số thay đổi trong Rails 4?


5
Khắc phục định dạng: params.require (: bill) .permit (: company ,: tháng ,: năm ,: dues_attribut => [: số tiền ,: person_id])
Andy Copley

Câu trả lời:


187

Có vẻ như có một sự thay đổi trong việc xử lý bảo vệ thuộc tính và bây giờ bạn phải liệt kê các tham số trong bộ điều khiển (thay vì attr_accessible trong mô hình) bởi vì gem_parameter tùy chọn trước đây đã trở thành một phần của Rails Core.

Cái này sẽ trông giống như thế này:

class PeopleController < ActionController::Base
  def create
    Person.create(person_params)
  end

private
  def person_params
    params.require(:person).permit(:name, :age)
  end
end

Vì vậy, params.require(:model).permit(:fields)sẽ được sử dụng

và cho các thuộc tính lồng nhau một cái gì đó như

params.require(:person).permit(:name, :age, pets_attributes: [:id, :name, :category])

Một số chi tiết khác có thể được tìm thấy trong các tài liệu API của Ruby edgestrong_parameter trên github hoặc tại đây


1
Tôi đã thay đổi BillContoder của mình thành như thế này: def bill_params params.require(:bill).permit(:company, :month, :year, :dues_attributes[:amount, :person_id]) end Bây giờ tôi đang gặp lỗi này: không có chuyển đổi ngầm định của Biểu tượng thành Số nguyên
jcanipar

2
Chà, nó giúp đặt dấu hai chấm vào đúng chỗ ... Đây chính xác là những gì cần phải làm. Cảm ơn @ thorsten-muller!
jcanipar

88
ĐỪNG QUÊN ID !!!! pets_attributes: [:id, :name, :category]Nếu không, khi bạn chỉnh sửa, mỗi thú cưng sẽ được tạo lại.
Arcolye

8
Bạn cần phải làm Person.create(person_params)hoặc nó sẽ không gọi phương thức. Thay vào đó bạn sẽ nhận được ActiveModel::ForbiddenAttributesError.
andorov

16
Ngoài ra, nếu bạn muốn hủy các mục từ biểu mẫu, bạn cũng cần đưa danh sách trắng vào :_destroytham số ẩn . tức làpets_attributes: [:id, :name, :category, :_destroy]
mầm bệnh

21

Từ các tài liệu

To whitelist an entire hash of parameters, the permit! method can be used

params.require(:log_entry).permit!

Các thuộc tính lồng nhau ở dạng băm. Trong ứng dụng của mình, tôi có một mô hình Câu hỏi.rb chấp nhận các thuộc tính lồng nhau cho mô hình Trả lời (trong đó người dùng tạo các lựa chọn trả lời cho câu hỏi mà anh ta tạo). Trong câu hỏi_controll, tôi làm điều này

  def question_params

      params.require(:question).permit!

  end

Mọi thứ trong hàm băm câu hỏi đều được cho phép, bao gồm các thuộc tính câu trả lời lồng nhau. Điều này cũng hoạt động nếu các thuộc tính lồng nhau ở dạng một mảng.

Có nói rằng, tôi tự hỏi liệu có một mối quan tâm bảo mật với phương pháp này bởi vì về cơ bản nó cho phép bất cứ thứ gì bên trong hàm băm mà không xác định chính xác nó là gì, dường như trái với mục đích của các tham số mạnh.


Tuyệt vời, tôi không thể cho phép một tham số phạm vi rõ ràng, điều này giúp tôi tiết kiệm một vài giờ.
Bartek Skwira

3
Vâng, sử dụng .permit! thường được xem là một mối quan tâm an ninh tiềm năng. Bạn chỉ thực sự muốn sử dụng nó nếu người dùng là quản trị viên, nhưng ngay cả khi đó tôi cũng sẽ cảnh giác với việc sử dụng nó.
8bithero

6
Các thuộc tính lồng nhau của tôi cũng nằm trong một mảng. Là .permit!lựa chọn duy nhất? Tôi không thể làm cho nó hoạt động ngay cả với tất cả các thuộc tính của mô hình được phép vì nó bị kẹt trên mảng.
Clifton Labrum

20

hoặc đơn giản là bạn có thể sử dụng

def question_params

  params.require(:question).permit(team_ids: [])

end

12

Trên thực tế có một cách để chỉ liệt kê danh sách trắng tất cả các tham số lồng nhau.

params.require(:widget).permit(:name, :description).tap do |whitelisted|
  whitelisted[:position] = params[:widget][:position]
  whitelisted[:properties] = params[:widget][:properties]
end

Phương pháp này có lợi thế hơn các giải pháp khác. Nó cho phép cho phép các tham số lồng nhau sâu.

Trong khi các giải pháp khác như:

params.require(:person).permit(:name, :age, pets_attributes: [:id, :name, :category])

Đừng.


Nguồn:

https://github.com/rails/rails/issues/9454#issuecomment-14167664


3

Hôm nay tôi đã gặp vấn đề tương tự, trong khi làm việc trên đường ray 4, tôi đã có thể làm cho nó hoạt động bằng cách cấu trúc các trường của tôi như:

<%= f.select :tag_ids, Tag.all.collect {|t| [t.name, t.id]}, {}, :multiple => true %>

Sau đó, trong bộ điều khiển của tôi, tôi có các thông số mạnh như:

private
def post_params
    params.require(:post).permit(:id, :title, :content, :publish, tag_ids: [])
end

Tất cả các công việc!


chào cảm ơn bạn @KingsleyIjomah - nếu bạn muốn liệt kê các thuộc tính cụ thể của trẻ em thì sao?
BKSpurgeon

1

Nếu bạn sử dụng trường JSONB, bạn phải chuyển đổi nó thành JSON với .to_json (ROR)

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.