无法使用Devise批量分配受保护的属性以创建has_many嵌套模型

我已经看过RailsCast,另一个嵌套属性video,很多SOpost,并与此争吵了一段时间,但我仍然无法弄明白。 我希望它有点小。

我有两个模型, User (由Devise创建)和Locker (又名产品愿望清单),我正在尝试为User注册时创建一个Locker 。 我的登录表单有一个新的Locker名称字段(恰当地称为:name ),我试图分配给在新用户注册时创建的锁定器。 我所遇到的只有:

WARNING: Can't mass-assign protected attributes: locker

我已经在我的两个模型中尝试了accepts_nested_attributesattr_accesible每个组合,但仍然attr_accesible 。 我可以从日志中看到它正在由Devise #create方法处理,我知道Devise不够聪明,无法创建我想要的模型:)

这是我的两个模型的相关部分:

 # user.rb class User  :lockers # Model nesting access accepts_nested_attributes_for :lockers end 

 # locker.rb class Locker  :lockups attr_accessible :name, :description end # lockers_controller.rb (create) @locker = current_user.lockers.build(params[:locker]) @locker.save 

我假设我需要覆盖Devise的create方法以某种方式让它工作,但我对rails非常新,并且我已经习惯了黑盒子“神奇”的本质。

如果有人能帮助我,我会非常感激。 已经花了太多时间在这上面,因为它是:)

编辑:我意识到我在我的问题中省略了一些东西。 我的Locker模型有三个属性 – namedescription (非强制)和user_id将其链接回User 。 我的注册表单只需要name ,所以我没有循环遍历嵌套表单中的所有属性。 这可能与我的问题有关吗?

编辑2:我也想出了如何覆盖Devise的RegistrationsController#create #create方法,我只是不知道该放什么。 Devise的整个resource对我来说没有意义,浏览他们的RegistrationsController的源代码也没有帮助我。

并且对于奖励积分:当用户使用无效数据提交登录表单时, Locker字段始终返回空白,同时填写常规设备字段,用户名和电子邮件。这是否也可以轻松修复? 如果是这样,怎么样?

首先,你有一个错字:

 attr_accessible :locker_attributes 

应该是复数:

 attr_accessible :lockers_attributes 

那么,使用nested_attributes的标准方法是:

 <%= form_for @user do |f| %> <%# fields_for will iterate over all user.lockers and build fields for each one of them using the block below, with html name attributes like user[lockers_attributes][0][name]. it will also generate a hidden field user[lockers_attributes][0][id] if the locker is already persisted, which allows nested_attributes to know if the locker already exists of if it must create a new one %> <% f.fields_for :lockers do |locker_fields| %> <%= locker_fields.label :name %> <%= locker_fields.text_field :name %> <% end %> <% end %> 

在你的控制器:

 def new @user = User.new @user.lockers.build end def create # no need to use build here : params[:user] contains a # :lockers_attributes key, which has an array of lockers attributes as value ; # it gets assigned to the user using user.lockers_attributes=, # a method created by nested_attributes @user = User.new( params[:user] ) end 

作为旁注,您可以避免以不同方式为控制器中的新用户构建新的锁定器:

  • User上创建工厂方法,或覆盖new ,或使用after_initialize回调以确保每个实例化的新用户都自动after_initialize一个锁定器

  • 将特定对象传递给fields_for

     <% f.fields_for :lockers, f.object.lockers.new do |new_locker_fields| %> 

有人帮助我以更“Rails 4’y”的方式找出解决方案,具有strong attributes以及如何覆盖Devise的sign_up_params (以捕获来自我的注册表单的所有数据)。

  def sign_up_params params.require(:user).permit(:username, :email, :password, :lockers_attributes) end 

Gemfile补充: gem 'strong_parameters'

在我的user.rb文件中attr_accessible语句,因为明显强大的参数消除了对attr_accessible声明的需要。

  # attr_accessible :username, :email, :password, :password_confirmation, :lockers 

和/在提交表单之前构建Locker的正确方法:在嵌套表单的开头:

<%= l.input :name, :required => true, label: "Locker name", :placeholder => "Name your first locker" %>

再次感谢你的帮助。 我知道如果没有看到整个代码库,很难回答这样的问题。