65.9K
CodeProject 正在变化。 阅读更多。
Home

Rails 3.2:嵌套表单演示,第二部分:加速攻击速度!

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (1投票)

2013 年 1 月 28 日

CPOL

5分钟阅读

viewsIcon

11277

Rails 3.2:嵌套表单演示,第二部分

概述

在我们上一篇文章中,我们勇敢的英雄们正飞速驶入“星际战斗机识别指南”的战壕。他们操纵着应用程序的整体结构,在自己(Pilots)和他们驾驶的Ships之间建立了一种关系。在这篇文章中,我们王牌反抗军飞行员将着陆,进入我们的应用程序表面。

控制器

由于所有繁重的工作都由我们领域模型中定义的ActiveRecord配置处理,所以Ship模型的控制器是相当标准的。快速回顾一下,ships_controller中的create方法看起来是这样的:

  def create
    @ship = Ship.new(params[:ship])

    if @ship.save
      redirect_to(ships_path, :notice => "The #{ @ship.name } ship has been saved successfully.")
    else
      render(:new, :error => @ship.errors)
    end
  end

如果您有兴趣查看整个控制器,可以在这里查看。

辅助方法

借鉴Railscast的灵感,我添加了几个辅助方法来让我的生活更轻松。

app/helpers/application_helper.rb

module ApplicationHelper
  def link_to_remove_fields(name, f, options = {})
    f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)", options)
  end

  def link_to_add_fields(name, f, association, options = {})
    new_object = f.object.class.reflect_on_association(association).klass.new
    fields = f.fields_for(association, new_object, :child_index => "new_#{ association }") do |builder|
      render(association.to_s.singularize + "_fields", :f => builder)
    end

    link_to_function(name, "add_fields(this, \"#{ association }\", \"#{ escape_javascript(fields) }\")", options)
  end
end

上面的代码几乎是直接从Railscast复制过来的,但我仍然认为值得回顾一下。

  • link_to_remove_fields:这个方法将创建一个隐藏的_destroy字段(告诉我们记录是否应该被删除)和一个超链接,该链接将调用一个javascript方法来更新我们的_destroy字段。
  • link_to_add_fields:这个方法将
    • 创建一个我们关联对象的新实例(在这种情况下是新的Pilot)。
    • 构建一个我们可以用来编辑新Pilot对象的表单。
    • :child_index将是一个占位符,将被javascript生成的唯一值替换(稍后会详细介绍)。
    • 构建一个包含我们Pilot对象的表单的超链接。

fields_for方法

让我们看看link_to_add_fields的第二行和第三行(上面代码的第8行和第9行)发生了什么。我们正在使用fields_for方法为我们构建Pilot的输入字段。从宏观上看,fields_for方法允许我们构建一个不带<form>标签的HTML表单。这意味着我们可以毫无问题地将我们的字段放入“父”表单中。

fields_for方法接受几个参数:

  • record_name:我们要创建的记录类型的名称。在这种情况下,我们将为这个参数传递“Pilots”。
  • record_object:我们要添加/编辑的对象的一个实例。在这种情况下,它将是一个Pilot对象。我们在link_to_add_fields方法的上一行(上面代码的第7行)创建了一个新的Pilot对象。
  • options:我们可以传递给fields_for方法的任何选项。在这种情况下,我们希望有一种方法来唯一标识我们创建的每个Pilot。因此,我们使用:child_index,并将其设置为一个“占位符”。对于这个特定的例子,我们的占位符文本将是“new_pilots”。当表单显示时(即调用add_fields javascript方法时),这个占位符将被一个唯一的标识符替换。

在我们的fields_for块中,我们要求它渲染我们的_pilot_fields.html.erb部分视图。注意第二个参数,:f => builder是父表单(即包含我们正在处理的Ship的输入字段的表单)。这意味着我们在调用fields_for时渲染的Pilot字段将是“添加飞船”表单的一部分,这正是我们想要的。

此时,我们的fields变量应该看起来有点像这样(为了可读性而整理了一下)。

© . All rights reserved.