Rails 4动态表单字段和表单对象

时间:2014-09-28 15:01:51

标签: ruby-on-rails-4 nested-forms

我有一组相当复杂的模型和关联,我希望我的应用程序的用户能够以单一形式输入所有这些的信息。这似乎是表单对象的工作。所以我做到了,它工作正常。但是我很难理解如何动态添加表单字段。因此,如果教授对象has_many论文如何将表单添加到表单中,因为表单对象不具有accepts_nested_parameters_for之类的内容?

我做了一个你可以看到的最小工作示例。该示例适用于添加三个彼此相关的模型。但是,我不知道如何动态添加表单字段并将它们与某些模型的新实例相关联。 https://github.com/blackfist/formobj。我将表单对象和控制器放在这里,但如果您需要更多上下文,请查看回购。

关于这方面的内容有很多教程,但我无法找到统一的来源。例如,有关表单对象的教程,但没有动态添加的字段。或者当您获得ccepts_nested_parameters_for时动态添加字段的示例。另外,我看到很多指向link_to_function的东西,我理解在Rails 4中不推荐使用。所以我不想在这里使用它作为解决方案。

这是表单对象

class ProfessorForm
  include ActiveModel::Model

  attr_accessor :prof_name, :prof_subject,
    :uni_name, :uni_state, :uni_city, :paper_title, :paper_date,
    :paper_publication

  validates :prof_name, presence: true
  validates :uni_name, presence: true
  validates :paper_title, presence:true

  def save
    if valid?
      persist!
      true
    else
      false
    end
  end

  def model_name
    Professor.model_name
  end

  private
    def persist!
      @uni = University.create!(name: uni_name, city:uni_city, state: uni_state)
      @pro = @uni.professors.create!(name: prof_name, subject: prof_subject)
      @pap = @pro.papers.create!(title: paper_title, date:paper_date, publication: paper_publication)
    end

end

和教授控制员

class ProfessorsController < ApplicationController
  def index
    @professors = Professor.all
  end

  def new
    @professor_form = ProfessorForm.new
  end

  def create
    @professor_form = ProfessorForm.new(professor_params)

    respond_to do |format|
      if @professor_form.save
        format.html {redirect_to professors_url, notice: 'Professor created successfully.' }
      else
        format.html { render :new }
      end
    end

  end

  private
    def professor_params
      params.require(:professor).permit(:prof_name, :prof_subject,
        :uni_name, :uni_city, :uni_state, :paper_title, :paper_date,
        :paper_publication)
    end
end

2 个答案:

答案 0 :(得分:0)

要动态添加或删除相关模型的字段,您可以尝试Ryan Bates的gem 'nested_forms'。它允许您在单个表单提交中添加多个记录。我不认为表单对象可以解决您的问题。

基本上安装完成后,您可以将以下代码放入视图中:

<%= f.fields_for :papers do |paper_form| %>
  <%= paper_form.text_field :name %>
  <%= paper_form.link_to_remove "Remove this paper" %>
<% end %>
<p><%= f.link_to_add "Add a paper", :papers %></p>

link_to_addlink_to_remove创建或删除字段,并在提交中动态创建多个记录。

此外,我不确定您的表单对象是否需要attr_reader :model_name才能正常工作。

答案 1 :(得分:0)

我知道很久以前就问过这个问题了,但仍然试着回答这个问题,突然之间它会对某人有所帮助。
我建议使用virtus gem。它允许您在表单类上定义属性。因此,您可以创建Paper类:

class Paper
  include Virtus.model

  attribute :title, String
  attribute :date, Date
  attribute :publication, String
end

并将其包含在表单类中。因此,您的ProfessorForm将如下所示:

class ProfessorForm
  include ActiveModel::Model
  include Virtus.model

  attribute :name
  attribute :subject
  attribute :papers, Array[Paper]

  ...
end
控制器中的

professor_params将以这种方式定义:

def professor_params
  params.require(ProfessorForm.new).permit(...)
end

并更改create方法以迭代纸张数组并创建它们:

def create
  @professor_form = ProfessorForm.new(professor_params)
  respond_to do |format|
    if @professor_form.valid?
      professor = Professor.create!(name: professor_params[:name], subject: professor_params[:subject])
      professor_params[:papers].each do |professor_paper|
        professor.papers.create!(title: professor_paper[:title], date: professor_paper[:date], publication: professor_paper[:publication])
    else
      format.html { render :new }
    end
  end
end

我没有提及University及其与Professor的关联,但也可以这样做。