2013-04-10 2 views
111

Я новичок в RoR, но решил, что могу, а также научиться на 4. Это может быть или не быть хорошей идеей. Я пытаюсь создать форму, используя вложенные атрибуты, и я боюсь.Rails 4 Вложенные атрибуты Неперечисленные параметры

Я просмотрел этот railscast http://railscasts.com/episodes/196-nested-model-form-part-1, и я пытаюсь воссоздать подобную ситуацию самостоятельно.

У меня есть Bill объект, который имеет много Долг объектов. Объект Due также принадлежит к Лицо. Я хочу форму, где я могу создать Билл и его детей Сборы все на одной странице.

Правильные поля отображаются на странице (хотя без выпадающего списка для лица еще) и отправить успешно. Тем не менее, ни один из детей сборов не сохраняются в базе данных и выдается ошибка в журнале сервера:

Unpermitted parameters: dues_attributes

Были ли какие-то изменения в Rails 4, или я просто совершенно не хватает что-то.

Просто перед ошибкой, протокол показывает это:

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



Соответствующий код приведен ниже

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 


счета/_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 %> 


би LLS/_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 в bills_controller.rb: Это работает!

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

Фикса на форматировании: params.require (Билл).(: company,: month,: year,: dues_attributes => [: amount, person_id]) –

ответ

163

Кажется есть изменения в обращении защиты атрибутов, и теперь вы должны белый список PARAMS в контроллере (вместо 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]) 

Некоторые подробности можно найти в Ruby edge API docs и strong_parameters on github или here

+1

Я изменил свой BillController, чтобы выглядеть так: 'def bill_params params.require (: bill) .permit (: компания: месяц,: год: dues_attributes [: сумма,: person_id]) end' Сейчас я получаю эту ошибку: ** не неявное преобразование символа в Integer ** – jcanipar

+2

Ну, это не помогает поместите двоеточие в нужное место ... Это именно то, что нужно сделать. Спасибо @ thorsten-muller! – jcanipar

+81

НЕ ЗАБУДЬТЕ ИД !!!! 'pets_attributes: [: id,: name,: category]' В противном случае при редактировании каждое домашнее животное будет создано снова. – Arcolye

18

Из документов

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 

Все в вопросе хэша допускается, в том числе атрибуты вложенным ответа. Это также работает, если вложенные атрибуты находятся в форме массива.

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

+0

Удивительно, я не могу разрешить параметр диапазона явно, это избавит меня несколько часов. –

+2

Да, используя .permit! обычно рассматривается как потенциальная проблема безопасности. Вы бы действительно хотели использовать его, если пользователь является администратором, но даже тогда я буду опасаться его использования. – 8bithero

+6

Мои вложенные атрибуты также находятся в массиве. Опция '.permit!' Единственная опция? Я не могу заставить его работать даже со всеми атрибутами модели, которые разрешены, потому что он зажимает массив. –

16

или вы можете просто использовать

def question_params 

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

end 
+0

спасибо, я могу разрешить params, которые принимают массив сейчас –

10

На самом деле есть способ просто белый список всех вложенных параметров.

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/issues/9454#issuecomment-14167664

3

Сегодня я наткнулся на этот же вопрос, в то время работал на рельсах 4, я был в состоянии заставить его работать за счет структурирования моего fields_for как:

<%= 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 

Все работы!

+0

привет спасибо @KingsleyIjomah - что, если вы хотите, чтобы белый список конкретных атрибутов детей? – BKSpurgeon

1

Если вы используете поле JSONB, вы должны преобразовать его в формат JSON с .to_json (ROR)

Смежные вопросы