Вкладені атрибути недозволені параметри


127

У мене є Billоб’єкт, у якого багато Dueоб’єктів. DueОб'єкт також належить до Person. Я хочу форму, яка може створювати Billі її дітей, Duesвсе на одній сторінці. Я намагаюся створити форму, використовуючи вкладені атрибути, схожі на ті, що в цьому Railscast .

Відповідний код наведено нижче:

належне.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

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

bills / _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 Це працює!

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

Належні поля відображаються на сторінці (хоч і поки не випадає Person) та надсилання успішно. Однак жодна з дочірних внесків не зберігається в базі даних, і помилка передається в журнал сервера:

Unpermitted parameters: dues_attributes

Незадовго до помилки журнал відображає це:

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?


5
Виправлення форматування: params.require (: bill) .permit (: компанія,: місяць,: рік,: dues_attributes => [: сума,: person_id])
Енді Коплі

Відповіді:


187

Здається, змінилися в застосуванні захисту атрибутів, і тепер ви повинні додати параметри білого списку в контролері (замість attr_accessible в моделі), оскільки колишні необов’язкові дорогоцінні камені strong_parameters стали частиною Rails Core.

Це має виглядати приблизно так:

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

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

Так params.require(:model).permit(:fields)би використовувались

а для вкладених атрибутів щось подібне

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

Ще деякі подробиці можна знайти в документах API Ruby edge та strong_parameters в github або тут


1
Я змінив свій BillController так, щоб він виглядав так: def bill_params params.require(:bill).permit(:company, :month, :year, :dues_attributes[:amount, :person_id]) end я отримую цю помилку: немає неявного перетворення символу в цілий
ряд

2
Ну, це допомагає поставити товсту кишку в потрібне місце ... Це саме те, що потрібно зробити. Дякуємо @ thorsten-muller!
jcanipar

88
НЕ ЗАБУДУЙТЕ ІДЕЙ !!!! pets_attributes: [:id, :name, :category]Інакше, коли ви будете редагуватись, кожен вихованець буде створений заново.
Arcolye

8
Вам потрібно зробити Person.create(person_params)або він не викликатиме метод. Замість цього ви отримаєте ActiveModel::ForbiddenAttributesError.
andorov

16
Крім того, якщо ви хочете знищити елементи з форми, вам також потрібно додати білий список прихованого :_destroyпараметра. тобтоpets_attributes: [:id, :name, :category, :_destroy]
Збудник

21

Від док

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

params.require(:log_entry).permit!

Вкладені атрибути мають форму хеша. У своєму додатку у мене модель Question.rb приймає вкладені атрибути для моделі Answer.rb (де користувач створює вибір відповідей на створене ним питання). У контролері questions_controller я це роблю

  def question_params

      params.require(:question).permit!

  end

Дозволяється все в хеші запитання, включаючи вкладені атрибути відповіді. Це також працює, якщо вкладені атрибути мають форму масиву.

Сказавши це, мені цікаво, чи є проблема безпеки щодо цього підходу, оскільки він в основному дозволяє все, що знаходиться всередині хешу, не вказуючи, що саме таке, що здається всупереч призначенню сильних параметрів.


Дивовижно, я не можу чітко дозволити параметр діапазону, це заощадить мене кілька годин.
Bartek Skwira

3
Так, використовуючи. Дозволу! зазвичай розглядається як потенційна стурбованість безпекою. Ви б дуже хотіли ним користуватися, якщо користувач є адміністратором, але навіть тоді я б насторожено ставився до його використання.
8bithero

6
Мої вкладені атрибути теж є в масиві. Є .permit!єдиний варіант? Я не можу змусити його працювати навіть з усіма дозволеними атрибутами моделі, оскільки вона задавлюється масивом.
Кліфтон Лабрум


12

Насправді існує спосіб просто перелічити всі вкладені параметри.

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

Цей метод має перевагу перед іншими рішеннями. Це дозволяє дозволити глибоко вкладені параметри.

Хоча інші рішення, як:

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

Не варто.


Джерело:

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


3

Сьогодні я зіткнувся з цим самим випуском, працюючи на рейках 4, мені вдалося його працювати, структуруючи свої поля_для:

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

Тоді в своєму контролері у мене є сильні парами:

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

Все працює!


привіт, дякую @KingsleyIjomah - що робити, якщо ти хочеш додати список специфічних ознак дітей?
BKSpurgeon

1

Якщо ви використовуєте поле JSONB, ви повинні перетворити його в JSON за допомогою .to_json (ROR)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.