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?

jcanipar
sumber
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

thorsten müller
sumber
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.

Leahcim
sumber
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
Amit Agarwal
sumber
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

tidak ada yang istimewa di sini
sumber
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!

Kingsley Ijomah
sumber
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)

Schoofs Wouter
sumber