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

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 无法使用Devise批量分配受保护的属性以创建has_many嵌套模型前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我已经看过RailsCast,另一个嵌套属性视频,很多SO帖子,并与此争吵了一段时间,但我仍然无法弄明白.我希望它有点小.

我有两个模型,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| %>

猜你在找的Ruby相关文章