带有Rails的复杂形式

时间:2011-08-03 02:14:34

标签: ruby-on-rails model-view-controller

我有一个表单,我想同时创建父记录和子记录。举一个简单的例子,假设它是一家拥有第一个员工的公司。

在我的控制器中我做了类似的事情:

def new
    @company = Company.new
    @company.employees.new
end

在我看来:

<%= form_for(@company) do |form| %>

    <div>
        <%= form.label :name %>
        <%= form.text_field :name %>
    </div>

    <%= form.fields_for :employees do |employee_form| %>

        <div>
            <%= employee_form.label :name %>
            <%= employee_form.text_field :name %>
        </div>

    <% end %>

<% end %>

再次回到我的控制器中:

def create
    @company = Company.new(params[:company])
    @company.employees << Employee.new(params[:company][:employees_attributes]["0"])

    # save stuff
end

问题1:

我无法在公司的员工集合中填充表单中创建的单个员工。当我查看params时,我找到了[:employees_attributes] [“0”]的东西。

我的工作是什么,但有更清洁的方法吗?

问题2:

如果验证没有通过员工,我会得到一个通用的“员工无效”,而不是名称要求的验证者消息。我得到的是我正在调用收集和rails正在尽力冒泡验证错误,但有没有更清晰的方法来做到这一点,所以我可以得到特定于员工的错误?

简而言之

如何清理它,以便从params自动创建相关模型,以便我获得单个员工的验证消息。

感谢您的光临。

1 个答案:

答案 0 :(得分:0)

1)fields_for安排将子对象属性嵌套在params散列中的父对象属性中,并将其发送回控制器动作。要让Rails自动更新子对象,请使用 accepts_nested_attributes_for 声明告诉父模型接受嵌套属性。

2)每个ActiveRecord对象都有一个错误对象。循环遍历错误列表并显示消息。

实现此目的的最佳方法是创建一个部分和一个视图助手方法,该方法将为您呈现错误。然后通过调用render_error_messages方法替换表单中生成的错误消息。您已经在生成的表单中拥有了所有代码。您只需要将该代码重构为部分代码,创建帮助程序 - 它应该接受一个模型名称数组作为参数,然后使用该信息执行您想要的操作。为每个模型渲染部分或渲染将处理子对象以及父对象的部分。完全是你的电话。

3)更改您的新操作以构建而不是创建新的子对象而不是

def new
    @company = Company.new
    @company.employees.new
end

这样做

def new
    @company = Company.new
    @company.employees.build
end

4)观看那些Railscast以了解accepts_nested_attributes的工作原理

http://railscasts.com/episodes/196-nested-model-form-part-1

http://railscasts.com/episodes/197-nested-model-form-part-2

<强>更新

那么上述信息如何与您的问题有关。

1)我的工作是什么,但是有更清洁的方法吗?

您已根据右上角的第3点修正了新动作?现在您的创建操作可能如下所示

def create
    @company = Company.new(params[:company])

    # save stuff
end

它更清晰,因为它已恢复到原始生成的创建操作。 您可能认为这不是更新,因此也不是那么清晰。孤立一点,你是对的。但是考虑到你可以添加任意数量的关系,你可以添加尽可能多的fields_for声明,你可以转换用户 - &gt;员工关系变成了has_many(我知道你不会)。你可以做到这一切,你的创建和更新动作保持完全相同,这就是为什么它更干净。

2)是否有更简洁的方法来执行此操作,以便我可以获取特定于员工的错误? 鉴于我在上面第2点的回答,您知道员工对象以及用户对象上有错误对象吗?您现在也知道可以遍历该错误对象以获取正确的消息吗? 所以你可以这样做

  <% if @user.employee.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.employee.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.employee.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

冒着重复自己的风险我只会说你应该将你的错误消息视图代码重构成一个部分,它将任何对象作为参数然后你可以从任何视图调用它,从而使你能够改变样式和所有表单的功能。

希望更清楚