使用accepts_nested_attributes_for时,在失败的创建操作上将params传递给新模板

时间:2011-09-21 01:00:01

标签: ruby-on-rails ruby-on-rails-3.1

我可能只是缺少一些简单的东西,但我相对缺乏经验,所以很可能。我已经广泛搜索了一个没有成功的解决方案。

我使用fields_for函数使用accepts_nested_attributes_for函数构建嵌套表单。如果表单上的提交失败,则params仅传递给父模型的新模板的渲染。如何为子模型传递嵌套参数,以便之前填充的字段保持填充状态。请注意,我使用的是simple_form和HAML,但我认为这不会对解决方案产生太大影响。

我的模特:

class Account < ActiveRecord::Base
  attr_accessible :name
  has_many :users,  :dependent => :destroy
  accepts_nested_attributes_for :users, :reject_if => proc { |a| a[:email].blank? }, :allow_destroy => true
end

class User < ActiveRecord::Base
  attr_accessible :email, :password, :password_confirmation
  belongs_to :account
end

我的帐户管理员:

def new
  @account = Account.new
  @account.users.build
end

def create
  @account = Account.new(params[:account])
  if @account.save
    flash[:success] = "Welcome."
    redirect_to @account
  else
    @account.users.build
                           <- I suspect I need something here but unsure what
    render :new
  end
end

帐户/新视图的关键部分:

= simple_form_for @account do |f|
  = f.input :name
  = f.simple_fields_for :users do |u|
    = u.input :email
    = u.input :password
    = u.input :password_confirmation
  = f.button :submit, :value => "Sign up"

我保存失败的参数是:

:account    {"name"=>"In", "users_attributes"=>{"0"=>{"email"=>"u@e.com", "password"=>"pass", "password_confirmation"=>"pass"}}}

如您所见,users_attributes部分中的关键信息已存储,但我似乎无法将电子邮件地址默认为新表单。另一方面,帐户名称根据Rails标准自动填充。我不确定解决方案是应该存在于帐户控制器中还是存在于帐户/新视图中,并且也没有任何运气。

使用.erb的答案当然没问题。

我是Ruby和Rails的新手,所以非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

问题在于attr_accessible,它指定了允许进行质量分配的 属性。

我感到有些愚蠢,因为我昨晚在评论中说出了这个问题并没有注意到:

  

accepts_nested_attributes_for:用户将向帐户添加users_attributes = writer以更新帐户的用户。

确实如此,但是对于attr_accessible :name,您已排除了每个属性,但名称是按质量分配的,users_attributes=包含在内。因此,当您通过Account.new(params[:account])建立新帐户时,会删除在参数中传递的users_attributes

如果您查看日志,则可能会注意到此警告:

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

您可以通过将:users_attributes添加到帐户类中的attr_accessible来电来解决原始问题,从而允许对其进行批量分配。

答案 1 :(得分:0)

令人惊讶的是,在今晚阅读了一篇博客文章后,还有更多的试验和错误,我自己也做了这个。

您需要在“新”操作中分配@user变量,以便用户参数可用于“创建”操作。然后,您需要在视图中同时使用@account@user变量。

这些变化看起来像这样。

帐户管理员:

def new
  @account = Account.new
  @user = @account.users.build
end

def create
  @account = Account.new(params[:account])
  @user = @account.users.build(params[:account][:user]
  if @account.save
    flash[:success] = "Welcome."
    redirect_to @account
  else        
    render :new
  end
end

帐户/新视图更改为:

= simple_form_for @account do |f|
  = f.input :name
  = f.simple_fields_for [@account, @user] do |u|
    = u.input :email
    = u.input :password
    = u.input :password_confirmation
  = f.button :submit, :value => "Sign up"

在这种情况下,参数仍然是嵌套的,但明确定义了user组件:

:account    {"name"=>"In", "user"=>{"email"=>"user@example.com", "password"=>"pass", "password_confirmation"=>"pass"}}

@account.users.build路径移除else会产生额外的副作用,因为@ numbers1311407建议

我不确定他们是否是这个解决方案的其他含义,我将需要在接下来的几天内完成它,但是现在我在失败的情况下得到了我想要默认进入视图的信息{{ 1}}行动。

@Beerlington和@ numbers1311407我很感谢帮助指导我解决问题。