我有两个模型,User(由Devise创建)和Locker(又名产品愿望清单),我正在尝试为用户注册时创建一个Locker.我的登录表单有一个新的Locker名称字段(恰当地称为:name),我试图分配给在新用户注册时创建的锁定器.我所遇到的只有:
警告:无法批量分配受保护的属性:locker
我已经在我的两个模型中尝试了accepts_nested_attributes和attr_accesible的每个组合,但仍然无效.我可以从日志中看到它正在由Devise #create方法处理,我知道Devise不够聪明,无法创建我想要的模型:)
这是我的两个模型的相关部分:
# user.rb class User < ActiveRecord::Base attr_accessible :username,:email,:password,:password_confirmation,:remember_me,:locker_attributes # Associations has_many :lockers has_many :lockups,:through => :lockers # Model nesting access accepts_nested_attributes_for :lockers end
和
# locker.rb class Locker < ActiveRecord::Base belongs_to :user has_many :lockups has_many :products,:through => :lockups attr_accessible :name,:description end # lockers_controller.rb (create) @locker = current_user.lockers.build(params[:locker]) @locker.save
我假设我需要覆盖Devise的创建方法以某种方式让它工作,但我对rails非常新,并且我已经习惯了黑盒子“神奇”的本质.
如果有人能帮助我,我会非常感激.已经花了太多时间在这上面,因为它是:)
编辑:我意识到我在我的问题中省略了一些东西.我的Locker模型有三个属性 – 名称,描述(非强制)和user_id将其链接回用户.我的注册表单只需要名称,所以我没有循环遍历嵌套表单中的所有属性.这可能与我的问题有关吗?
编辑2:我也想出了如何覆盖Devise的RegistrationsController #create方法,我只是不知道该放什么. Devise的整个资源对我来说没有意义,浏览他们的RegistrationsController的源代码也没有帮助我.
并且对于奖励积分:当用户使用无效数据提交登录表单时,Locker字段总是空白,而常规的Devise字段,用户名和&电子邮件,已填写.这也可以轻松修复吗?如果是这样,怎么样?
解决方法
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回调以确保每个实例化的新用户都自动构建一个锁定器
>将特定对象传递给fields_for:
<% f.fields_for :lockers,f.object.lockers.new do |new_locker_fields| %>