İç içe yerleştirilmiş özniteliklere izin verilmeyen parametreler


127

BillBirçok nesneye sahip bir nesnem var Due. DueNesne aynı zamanda bir aittir Person. BillVe alt öğelerini Duestek bir sayfada oluşturabilecek bir form istiyorum . Bu Railscast'dekine benzer şekilde iç içe özellikler kullanarak bir form oluşturmaya çalışıyorum .

İlgili kod aşağıda listelenmiştir:

due.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

faturaları / _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 %>

faturaları / _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>

Bills_controller.rb'ye GÜNCELLE Bu çalışıyor!

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

Sayfada uygun alanlar oluşturulur ( Personhenüz bir açılır menü olmasa da ) ve gönderme başarılı olur. Ancak, çocuk aidatlarının hiçbiri veritabanına kaydedilmez ve sunucu günlüğünde bir hata atılır:

Unpermitted parameters: dues_attributes

Hatadan hemen önce, günlük şunu görüntüler:

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

Rails 4'te bir değişiklik oldu mu?


5
Biçimlendirmeyle ilgili düzeltme: params.require (: bill) .permit (: şirket,: ay,: yıl,: dues_attributes => [: miktar,: kişi_kimliği])
Andy Copley

Yanıtlar:


187

Görünüşe göre öznitelik korumasının işlenmesinde bir değişiklik var ve şimdi denetleyicideki parametreleri beyaz listeye eklemelisiniz (modelde attr_accessible yerine) çünkü eski isteğe bağlı gem strong_parameters Rails Core'un bir parçası haline geldi.

Bu şuna benzer bir şeye benzemelidir:

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

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

Yani params.require(:model).permit(:fields)kullanılacak

ve iç içe geçmiş öznitelikler için

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

Ruby edge API belgelerinde ve strong_parameters'da github'da veya burada daha fazla ayrıntı bulunabilir.


1
BillController'ımı şu şekilde görünecek şekilde değiştirdim: def bill_params params.require(:bill).permit(:company, :month, :year, :dues_attributes[:amount, :person_id]) end Şimdi şu hatayı alıyorum: Sembolün
Tamsayıya

2
Pekala, kolonu doğru yere yerleştirmeye yardımcı oluyor ... Bu tam olarak yapılması gereken şey. Teşekkürler @ thorsten-muller!
jcanipar

88
KİMLİĞİ UNUTMAYIN !!!! pets_attributes: [:id, :name, :category]Aksi takdirde, düzenlediğinizde her evcil hayvan yeniden yaratılacaktır.
Arcolye

8
Yapman gerekiyor, yoksa Person.create(person_params)yöntemi çağırmaz. Bunun yerine alacaksın ActiveModel::ForbiddenAttributesError.
andorov

16
Ayrıca, formdaki öğeleri yok etmek istiyorsanız, gizli :_destroyparametreyi de beyaz listeye almanız gerekir . yanipets_attributes: [:id, :name, :category, :_destroy]
Pathogen

21

Dokümanlardan

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

params.require(:log_entry).permit!

İç içe geçmiş öznitelikler bir karma biçimindedir. Uygulamamda, bir Answer.rb modeli için yuvalanmış öznitelikleri kabul eden bir Question.rb modelim var (burada kullanıcı, oluşturduğu bir soru için yanıt seçenekleri oluşturur). Questions_controller'da bunu yapıyorum

  def question_params

      params.require(:question).permit!

  end

İç içe geçmiş yanıt öznitelikleri de dahil olmak üzere soru karmasındaki her şeye izin verilir. Bu, yuvalanmış öznitelikler bir dizi biçiminde olduğunda da işe yarar.

Bunu söyledikten sonra, bu yaklaşımla ilgili bir güvenlik endişesi olup olmadığını merak ediyorum çünkü temelde hash içindeki her şeye tam olarak ne olduğunu belirtmeden izin veriyor, bu da güçlü parametrelerin amacına aykırı görünüyor.


Harika, bir aralık parametresine açıkça izin veremiyorum, bu bana birkaç saat kazandırır.
Bartek Skwira

3
Evet, .permit kullanarak! genellikle potansiyel bir güvenlik sorunu olarak görülür. Sadece kullanıcı bir yönetici ise gerçekten kullanmak istersiniz, ancak o zaman bile kullanımına karşı dikkatli olurum.
8bithero

6
İç içe geçmiş niteliklerim de bir dizide. Mı .permit!Tek seçenek? Dizide boğulduğu için izin verilen tüm model öznitelikleriyle bile çalışmasını sağlayamıyorum.
Clifton Labrum

20

veya basitçe kullanabilirsiniz

def question_params

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

end

12

Aslında, iç içe geçmiş tüm parametreleri beyaz listeye almanın bir yolu var.

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

Bu yöntemin diğer çözümlere göre avantajı vardır. Derin yuvalanmış parametrelere izin verir.

Diğer çözümler şöyle olsa da:

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

Yapma.


Kaynak:

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


3

Bugün aynı sorunla karşılaştım, raylar 4 üzerinde çalışırken, field_for'umu şu şekilde yapılandırarak çalıştırmayı başardım:

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

Sonra denetleyicimde şu güçlü parametrelerim var:

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

Tüm işler!


merhaba teşekkür ederim @KingsleyIjomah - ya çocukların belirli özelliklerini beyaz listeye almak isterseniz?
BKSpurgeon

1

Bir JSONB alanı kullanıyorsanız, bunu .to_json (ROR) ile JSON'a dönüştürmelisiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.