Atribut bersarang parameter yang tidak diizinkan


127

Saya memiliki Billobjek, yang memiliki banyak Dueobjek. The Dueobjek juga milik Person. Saya ingin formulir yang dapat membuat Billdan anak-anaknya Duessemuanya dalam satu halaman. Saya mencoba membuat formulir menggunakan atribut bersarang, mirip dengan yang ada di Railscast ini .

Kode yang relevan tercantum di bawah ini:

karena.rb

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

bill.rb

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

bills_controller.rb

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

tagihan / _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 %>

tagihan / _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>

UPDATE ke bills_controller.rb Ini berfungsi!

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

Bidang yang tepat diberikan pada halaman (meskipun Personbelum ada dropdown ) dan pengiriman berhasil. Namun, tidak ada iuran anak-anak yang disimpan ke database, dan kesalahan dilemparkan ke log server:

Unpermitted parameters: dues_attributes

Tepat sebelum kesalahan, log menampilkan ini:

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"}

Apakah ada perubahan di Rails 4?


5
Memperbaiki pemformatan: params.require (: bill) .permit (: perusahaan,: bulan,: tahun,: dues_attributes => [: jumlah,: person_id])
Andy Copley

Jawaban:


187

Tampaknya ada perubahan dalam penanganan perlindungan atribut dan sekarang Anda harus memasukkan daftar putih pada pengontrol (alih-alih attr_accessible dalam model) karena bekas permata opsional strong_parameters menjadi bagian dari Rails Core.

Seharusnya terlihat seperti ini:

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

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

Jadi params.require(:model).permit(:fields)akan digunakan

dan untuk atribut bertingkat seperti

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

Beberapa perincian lebih lanjut dapat ditemukan di dokumen API Ruby edge dan strong_parameters di github atau di sini


1
Saya telah mengubah BillController saya menjadi seperti ini: def bill_params params.require(:bill).permit(:company, :month, :year, :dues_attributes[:amount, :person_id]) end Saya sekarang mendapatkan kesalahan ini: tidak ada konversi yang tersirat dari Symbol menjadi Integer
jcanipar

2
Yah, itu membantu untuk menempatkan usus besar di tempat yang tepat ... Inilah yang perlu dilakukan. Terima kasih @ thorsten-muller!
jcanipar

88
JANGAN LUPA ID INI !!!! pets_attributes: [:id, :name, :category]Jika tidak, saat Anda mengedit, setiap hewan peliharaan akan dibuat lagi.
Arcolye

8
Anda perlu melakukannya Person.create(person_params)atau tidak akan memanggil metode. Sebaliknya Anda akan mendapatkannya ActiveModel::ForbiddenAttributesError.
andorov

16
Selain itu, jika Anda ingin memusnahkan item dari formulir, Anda juga perlu memasukkan daftar putih :_destroyparameter yang disembunyikan . yaitupets_attributes: [:id, :name, :category, :_destroy]
Patogen

21

Dari dokumen

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

params.require(:log_entry).permit!

Atribut bersarang adalah dalam bentuk hash. Di aplikasi saya, saya memiliki model Question.rb menerima atribut bersarang untuk model Answer.rb (di mana pengguna membuat pilihan jawaban untuk pertanyaan yang ia buat). Dalam question_controller, saya melakukan ini

  def question_params

      params.require(:question).permit!

  end

Segala sesuatu dalam hash pertanyaan diizinkan, termasuk atribut jawaban bersarang. Ini juga berfungsi jika atribut bersarang dalam bentuk array.

Karena itu, saya bertanya-tanya apakah ada masalah keamanan dengan pendekatan ini karena pada dasarnya memungkinkan apa pun yang ada di dalam hash tanpa menentukan dengan tepat apa itu, yang tampaknya bertentangan dengan tujuan parameter yang kuat.


Luar biasa, saya tidak bisa mengizinkan parameter rentang secara eksplisit, ini menghemat beberapa jam.
Bartek Skwira

3
Ya, menggunakan .permit! biasanya dipandang sebagai masalah keamanan potensial. Anda hanya benar-benar ingin menggunakannya jika pengguna adalah admin, tetapi bahkan kemudian saya akan waspada terhadap penggunaannya.
8bithero

6
Atribut bersarang saya juga ada dalam array. Apakah .permit!satu-satunya pilihan? Saya tidak bisa membuatnya berfungsi bahkan dengan semua atribut model diizinkan karena tersedak array.
Clifton Labrum

20

atau Anda cukup menggunakan

def question_params

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

end

12

Sebenarnya ada cara untuk hanya daftar putih semua parameter bersarang.

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

Metode ini memiliki keunggulan dibandingkan solusi lain. Hal ini memungkinkan untuk mengizinkan parameter mendalam.

Sementara solusi lain seperti:

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

Jangan.


Sumber:

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


3

Hari ini saya menemukan masalah yang sama, saat bekerja pada rails 4, saya bisa membuatnya bekerja dengan menyusun bidang saya untuk:

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

Kemudian di controller saya, saya memiliki params kuat saya sebagai:

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

Semua bekerja!


hai terima kasih @ KingsleyIjomah - bagaimana jika Anda ingin membuat daftar atribut khusus anak-anak?
BKSpurgeon

1

Jika Anda menggunakan bidang JSONB, Anda harus mengonversinya ke JSON dengan .to_json (ROR)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.