Rails 4 разрешает вложенные атрибуты не создавать/обновлять

Я конвертирую свое приложение rails (-v3.2.13) в rails 4. Я использую действия по перезаписи унаследованных ресурсов gem (создание! и обновление!). Я разрешаю весь хэш параметров, но он не создает/обновляет вложенные атрибуты. Мне нужно разрешить весь хэш параметров. Когда я пытался, я получаю следующую ошибку. Помогите мне решить эту проблему.

параметры

{"foo"=>{"name"=>"1@1", "detail"=>"123", foo1_attributes"=>{"0"=>{"_destroy"=>"", "name"=>"John", "url"=>"johnsmith.blogspot.com",foo2_attributes"=>{"0"=>{"min_time"=>"0", "max_entry"=>"340"}}, "foo3_attributes"=>{"_destroy"=>"", "hours"=>"01", "minutes"=>"00"}, "status"=>"ACTIVE"}}, "foo4_attributes"=>{"0"=>{"image"=>"0","id"=>"1097"}}}, "commit"=>"Save", "foo_id"=>"13", "id"=>"1467"}

Мой контроллер

def update
 update! do |success, failure|
  success.html { redirect_to foo_path }
 end
end

protected

def resource_params
 params.permit!
end

Фу Модель

accepts_nested_attributes_for : foo1,foo2,foo3,foo4
has_many :foo1
has_many :foo2
has_many :foo3
has_many :foo4

След:

 Completed 500 Internal Server Error in 3686ms

 ArgumentError (wrong number of arguments (6 for 1..2)):
  app/controllers/foo_controller.rb:160:in `update'

 protected_attributes (1.0.3) lib/active_record/mass_assignment_security/persistence.rb:60:in `update_attributes'
inherited_resources (1.3.1) lib/inherited_resources/base_helpers.rb:78:in `update_resource'
inherited_resources (1.3.1) lib/inherited_resources/actions.rb:45:in `update'
app/controllers/partner_modules_controller.rb:160:in `update'
actionpack (4.0.0) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.0.0) lib/abstract_controller/base.rb:189:in `process_action'
actionpack (4.0.0) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.0.0) lib/abstract_controller/callbacks.rb:18:in `block in process_action'
activesupport (4.0.0) lib/active_support/callbacks.rb:445:in `block (2 levels) in _run__2668227825050344147__process_action__callbacks'
activesupport (4.0.0) lib/active_support/callbacks.rb:212:in `block in _conditional_callback_around_4134'
rails-observers (0.1.2) lib/rails/observers/action_controller/caching/sweeping.rb:73:in `around'
activesupport (4.0.0) lib/active_support/callbacks.rb:283:in `_callback_around_4133'
activesupport (4.0.0) lib/active_support/callbacks.rb:211:in `_conditional_callback_around_4134'
activesupport (4.0.0) lib/active_support/callbacks.rb:444:in `block in _run__2668227825050344147__process_action__callbacks'
activesupport (4.0.0) lib/active_support/callbacks.rb:215:in `_conditional_callback_around_4135'
activesupport (4.0.0) lib/active_support/callbacks.rb:443:in `_run__2668227825050344147__process_action__callbacks'
activesupport (4.0.0) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.0) lib/abstract_controller/callbacks.rb:17:in `process_action'
actionpack (4.0.0) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (4.0.0) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
activesupport (4.0.0) lib/active_support/notifications.rb:159:in `block in instrument'
activesupport (4.0.0) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (4.0.0) lib/active_support/notifications.rb:159:in `instrument'
actionpack (4.0.0) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (4.0.0) lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
activerecord (4.0.0) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (4.0.0) lib/abstract_controller/base.rb:136:in `process'
actionpack (4.0.0) lib/abstract_controller/rendering.rb:44:in `process'
actionpack (4.0.0) lib/action_controller/metal.rb:195:in `dispatch'
actionpack (4.0.0) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
actionpack (4.0.0) lib/action_controller/metal.rb:231:in `block in action'
actionpack (4.0.0) lib/action_dispatch/routing/route_set.rb:80:in `call'
actionpack (4.0.0) lib/action_dispatch/routing/route_set.rb:80:in `dispatch'
actionpack (4.0.0) lib/action_dispatch/routing/route_set.rb:48:in `call'
actionpack (4.0.0) lib/action_dispatch/journey/router.rb:71:in `block in call'
actionpack (4.0.0) lib/action_dispatch/journey/router.rb:59:in `each'
actionpack (4.0.0) lib/action_dispatch/journey/router.rb:59:in `call'
actionpack (4.0.0) lib/action_dispatch/routing/route_set.rb:655:in `call'
newrelic_rpm (3.6.6.147) lib/new_relic/rack/error_collector.rb:43:in `call'
bullet (4.6.0) lib/bullet/rack.rb:13:in `call'
newrelic_rpm (3.6.6.147) lib/new_relic/rack/error_collector.rb:43:in `call'
newrelic_rpm (3.6.6.147) lib/new_relic/rack/agent_hooks.rb:22:in `call'
newrelic_rpm (3.6.6.147) lib/new_relic/rack/browser_monitoring.rb:16:in `call'
warden (1.2.3) lib/warden/manager.rb:35:in `block in call'
warden (1.2.3) lib/warden/manager.rb:34:in `catch'
warden (1.2.3) lib/warden/manager.rb:34:in `call'
rack (1.5.2) lib/rack/etag.rb:23:in `call'
rack (1.5.2) lib/rack/conditionalget.rb:35:in `call'
rack (1.5.2) lib/rack/head.rb:11:in `call'
remotipart (1.2.1) lib/remotipart/middleware.rb:27:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/flash.rb:241:in `call'
rack (1.5.2) lib/rack/session/abstract/id.rb:225:in `context'
rack (1.5.2) lib/rack/session/abstract/id.rb:220:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/cookies.rb:486:in `call'
activerecord (4.0.0) lib/active_record/query_cache.rb:36:in `call'
activerecord (4.0.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:626:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.0.0) lib/active_support/callbacks.rb:373:in `_run__994999873434308059__call__callbacks'
activesupport (4.0.0) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.0) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/reloader.rb:64:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.0.0) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.0.0) lib/rails/rack/logger.rb:21:in `block in call'
activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `block in tagged'
activesupport (4.0.0) lib/active_support/tagged_logging.rb:25:in `tagged'
activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `tagged'
railties (4.0.0) lib/rails/rack/logger.rb:21:in `call'
quiet_assets (1.0.2) lib/quiet_assets.rb:18:in `call_with_quiet_assets'
actionpack (4.0.0) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
rack (1.5.2) lib/rack/runtime.rb:17:in `call'
rack (1.5.2) lib/rack/lock.rb:17:in `call'
actionpack (4.0.0) lib/action_dispatch/middleware/static.rb:64:in `call'
railties (4.0.0) lib/rails/engine.rb:511:in `call'
railties (4.0.0) lib/rails/application.rb:97:in `call'
rack (1.5.2) lib/rack/content_length.rb:14:in `call'
thin (1.5.1) lib/thin/connection.rb:81:in `block in pre_process'
thin (1.5.1) lib/thin/connection.rb:79:in `catch'
thin (1.5.1) lib/thin/connection.rb:79:in `pre_process'
thin (1.5.1) lib/thin/connection.rb:54:in `process'
thin (1.5.1) lib/thin/connection.rb:39:in `receive_data'
eventmachine (1.0.3) lib/eventmachine.rb:187:in `run_machine'
eventmachine (1.0.3) lib/eventmachine.rb:187:in `run'
thin (1.5.1) lib/thin/backends/base.rb:63:in `start'
thin (1.5.1) lib/thin/server.rb:159:in `start'
rack (1.5.2) lib/rack/handler/thin.rb:16:in `run'
rack (1.5.2) lib/rack/server.rb:264:in `start'
railties (4.0.0) lib/rails/commands/server.rb:84:in `start'
railties (4.0.0) lib/rails/commands.rb:78:in `block in <top (required)>'
railties (4.0.0) lib/rails/commands.rb:73:in `tap'
railties (4.0.0) lib/rails/commands.rb:73:in `<top (required)>'
script/rails:6:in `require'
script/rails:6:in `<main>'

person Mano    schedule 19.08.2013    source источник
comment
params.require(:foo).permit(:attr_of_foo, :another_attr_of_foo, :foo1_attributes => [:attr_of_foo1, :more_attr_of_foo1], ..so forth) вам не подходит?   -  person j03w    schedule 19.08.2013
comment
@jo3w Да, я пробовал с params.requir(:foo).permit(:name,:detail,foo1_attributes: [:name, :url]), но я получаю ошибку неправильного количества аргументов. Мне нужно разрешить весь хэш. Я что-то здесь упустил?   -  person Mano    schedule 19.08.2013
comment
Возможный дубликат stackoverflow.com/questions/17371334/   -  person Pierre-Louis Gottfrois    schedule 20.08.2013


Ответы (7)


Это может быть немного поздно, но я только что столкнулся с этим сам. Надеюсь, это сэкономит кому-то еще время.

Использование Rails 4.2.1

Проблема с другими ответами здесь заключается в том, что они не учитывают, что существует array для значения foo1_attributes:

(расширенный пример из OP)

foo1_attributes"=> {
  "0"=> {
     "_destroy"=>"", "name"=>"John", "url"=>"johnsmith.blogspot.com"
  }
}

Из-за этого вам нужно permit и foo1_attributes, и foo1_attributes[n]

Вот как я успешно реализовал подобную функциональность в своем проекте:

(отформатировано в соответствии с приведенным выше примером OP)

def resource_params
  params.require(:foo)
    .permit(
      :id,
      :name,
      :detail,

      # has_many: :foo1s (Nested Attributes)
        { foo1_attributes: [
          # and the values for each `foo1` in `foo1_attributes`
          [
            :name,
            :url
          ]
        ]},

      # has_many: :foo2s (Nested Attributes)
        { foo2_attributes: [
          # and the values for each `foo2` in `foo2_attributes`
          [
            :min_time,
            :max_entry
          ]
        ]}

      # etc...
    )

Некоторые другие вещи, чтобы отметить...

person Eric Norcross    schedule 07.07.2015

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

def foo_params
  params.require(:foo).permit(:foo1_attributes => [:bar1 , :bar2])
end

Делайте обновление через.

def update  
  if @foo.update_attributes!(foo_params)      
    redirect_to foo_path
  else
    render foo1_edit_path
  end
end
person xvidun    schedule 14.12.2013

привет, вы должны использовать его следующим образом:

params.require( :foo ).permit( :name, :details, foo1_attributes: [ :_destroy, :name, :url, :id ], foo2_attributes: [ :_destroy, :min_time, :max_entry, :id ] )

Это может решить вашу проблему.

person Akshat    schedule 04.11.2013
comment
здесь помните, что идентификатор вложенных атрибутов не требуется в случае создания, но он обязателен при обновлении вложенных атрибутов, иначе он создаст для вас новую копию. Вот почему я добавил поле id в поля разрешений вложенных атрибутов. - person Akshat; 04.11.2013

Как указано в README с сильными параметрами, вы можете использовать метод permit! для внесения в белый список весь хэш параметров следующим образом:

params.require(:foo).permit!

Пожалуйста, имейте в виду следующую цитату из документа README, связанного с этим:

Будьте предельно осторожны при использовании разрешения! поскольку это позволит массово назначать все текущие и будущие атрибуты модели.

person vee    schedule 19.08.2013
comment
Это не работает. Тем не менее я получаю неправильное количество аргументов. - person Mano; 19.08.2013
comment
Можете ли вы опубликовать полную трассировку в своем вопросе, когда возникает эта ошибка. - person vee; 19.08.2013
comment
@Мано, это все? Должно быть больше, потому что я не вижу ошибки, о которой вы говорите. - person vee; 19.08.2013
comment
@Mano, попробуйте вызвать update! с параметром resource_params, т.е. в вашем действии обновления выполните update!(resource_params) do |success, failure| - person vee; 19.08.2013
comment
О боже спасибо! Я слишком долго писал бесконечные вызовы Permit(.....) для совершенно некритичных моделей. Я не знал, что это так просто! - person Tigraine; 19.05.2015

Замените текущие сильные параметры следующим:

def permitted_params
    params.permit(:widget => [:permitted_field, :other_permitted_field])
end

Дополнительная информация: https://github.com/josevalim/inherited_resources#strong-parameters

person Richard Peck    schedule 03.10.2013

Я считаю, что ваш метод resource_params должен называться permitted_params. Дополнительные сведения о том, как обрабатывать сильные параметры, см. в документации по унаследованным ресурсам.

person Chris Fritz    schedule 09.09.2013

Я не думаю, что это серьезная ошибка, связанная с параметром. В Rails 4.0, если параметр не внесен в белый список, он автоматически терпит неудачу и объект не создается. У меня была эта ошибка некоторое время назад, и я точно не знаю, как ее исправить, но можете ли вы опубликовать свой файл route.rb и включить методы new и create в свой контроллер? Я почти уверен, что ваша ошибка связана с вложением ресурсов.

person Michael Choi    schedule 01.11.2013