【问题标题】:Complex form with RailsRails 的复杂形式
【发布时间】:2011-08-03 02:14:33
【问题描述】:

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

在我的控制器中,我执行以下操作:

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:

我无法让公司的员工集合填充表单中创建的单个员工。当我查看参数时,我发现了 [:employees_attributes]["0"] 的东西。

我有什么工作,但有没有更清洁的方法来做到这一点?

问题 2:

如果员工的验证未通过,我会收到一个通用的“员工无效”,而不是 Name required 验证器消息。我知道我在集合上调用 save 并且 Rails 正在尽最大努力将验证错误冒泡,但是有没有更简洁的方法可以做到这一点,以便我可以获取特定于员工的错误?

简而言之

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

感谢收看。

【问题讨论】:

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


    【解决方案1】:

    1) fields_for 安排子对象属性嵌套在 params 哈希中的父对象属性中,该参数哈希被发送回控制器操作。要让 Rails 自动更新子对象,请使用 accepts_nested_attributes_for 声明告诉父模型接受嵌套属性。

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

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

    3) 将您的新操作更改为 build 而不是创建一个新的子对象,而不是

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

    这样做

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

    4) 观看那些 Railscast 以了解 accept_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 声明,您可以将用户-> 员工关系转换为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 %>
    

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

    希望这更清楚

    【讨论】:

    • 感谢您的回复。我已经在父模型中设置了accepts_nested_attributes_for。我也已经有一个部分执行 model.errors.full_messages.each 我得到的是“员工无效”,而不是“名称不能为空”。在我阅读了两者之间的细微差别之后,关于构建的建议是有道理的,谢谢。在寻求帮助之前,我已经看过 Railscasts。不知道这会给我留下什么,任何其他想法都会很棒,但不确定我还能提供什么。再次感谢。
    • 我确实涵盖了这些观点,但也许我说的不够清楚。我会更新我的答案以使其更清楚
    • @blu - 我已经更新了我的答案,希望你现在可以看到如何使用我给你的信息
    • @blu - 现在对你有用吗?如果没有,我会尽力消除任何误解
    • 我得回去再看一遍,一直很忙。 #1 听起来不错,这就是我的目标,但我似乎无法让它发挥作用。
    猜你喜欢
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多