是否可以在 1 个视图中从两个表单创建两个 objects 并将它们相关联?

Is it possible to create two objects from two forms in 1 view and have them related?

我知道标题听起来有点靠不住,但这就是我想要做的。

我有两个模型 - JobCompany。有人可以创建职位列表,但在保存列表之前,它应该与公司相关联。这家公司可以是新创建的,或者应该从 current_user 之前创建的公司中填充。

一个job belongs_to :company和一个company has_many :jobs.

我知道我可以做两个不同的视图,只需将用户发送到两个不同控制器上的两个不同操作,但我想简化它并在一个视图中完成所有操作。

当他们转到 /jobs/new 时,他们应该会看到正常的 jobs/_form.html.erb 部分,但我希望能够显示现有公司或新公司创建字段的公司下拉列表用户填写,新公司与正在创建的新工作相关联。

这是我的 jobs/_form.html.erb 部分的样子:

<%= simple_form_for(@job) do |f| %>
    <%= f.input_field :title %>
    <%= f.input_field :salary %>
    <%= f.input_field :description, as: :text %>
    <%= f.input_field :apply_description, as: :text %>
    <%= f.input_field :language %>
    <%= f.input :premium, as: :boolean, inline_label: true, label: "Make this listing stand out",  class: "form-control" %>
    <%= f.button :submit, class: "btn btn-lg btn-primary pull-right" %>
<% end %>

这是我的 companies/_form.html.erb 的样子:

<%= simple_form_for(@company) do |f| %>
    <%= f.input :name %>
    <%= f.input :logo %>
    <%= f.input :description %>
    <%= f.input :city %>
    <%= f.input :state %>
    <%= f.input :country %>
    <%= f.input :email %>
    <%= f.button :submit %>
<% end %>

如何将它们合并为 1 个表单,或在 1 个视图中合并为用户无缝工作的其他统一工作流程?

编辑 1

根据Jay-Ar的回答,这就是现在发生的事情。

当我在公司下拉列表中 select New Company 时,它不显示 <fieldset> 中的字段。我认为是这种情况,因为在 HTML 中呈现的 select 标签中没有 value=0,如下面的屏幕截图所示。

编辑 2

尝试 Jay-Ar 的最新更新后,JS 仍然无法正常工作,表单不再隐藏。

这是第一次加载时的样子,而且总是这样:

理想情况下,我希望在他们从下拉列表中选择 "New Company" 之前不要显示此表单。

这就是 HTML 现在的样子:

JS 确实出现在源代码中,所以我知道它正在正确加载到资产管道中。

你应该使用嵌套模型表单,我建议你看一下这个video它对问题/答案模型的步骤进行了非常详细的解释,但它是一回事。

更新和测试工作

  • 现在支持 Turbolinks

views/jobs/_form.html.erb

<%= simple_form_for(@job) do |f| %>
  <%# IMPORTANT: use `include_blank` below instead of `prompt` because prompt does not seem to work when updating, but only works when creating %>
  <%= f.association :company, collection: [['New Company', nil]] + Company.pluck(:name, :id), include_blank: 'Please Select Company', input_html: { id: 'company-select' } %>
  <fieldset id='job-fields'>
    <%= f.simple_fields_for :company, @job.build_company do |ff| %>
      <%= ff.input :name %>
      <%= ff.input :logo %>
      <%= ff.input :description %>
      <%= ff.input :city %>
      <%= ff.input :state %>
      <%= ff.input :country %>
      <%= ff.input :email %>
    <% end %>
  </fieldset>
  <%= f.input_field :title %>
  <%= f.input_field :salary %>
  <%= f.input_field :description, as: :text %>
  <%= f.input_field :apply_description, as: :text %>
  <%= f.input_field :language %>
  <%= f.input :premium, as: :boolean, inline_label: true, label: "Make this listing stand out",  class: "form-control" %>
  <%= f.button :submit, class: "btn btn-lg btn-primary pull-right" %>
<% end %>

JS

// for Rails 5, use turbolinks:load instead of page:change below
$(document).on('page:change', function(){
  var companySelect = $('#company-select');
  var jobFields = $('#job-fields');

  companySelect.change(function(){
    // if selected option is the second option
    if ($(this).find('option:selected').index() == 1)
      jobFields.show().find(':input').prop('disabled', false);
    else
      jobFields.hide().find(':input').prop('disabled', true);
  })
  // call change immediately so this still works when already updating and not just creating.
  companySelect.change();
})

controllers/jobs_controller.rb

class JobsController < ApplicationController
  ...
  def create
    @job = Job.new(job_params)
    ...
  end

  def update
    @job = Job.find(params[:id]) # not needed if using before_action #set_job
    if @job.update(job_params)
    ...
  end

  private

  def job_params
    params.require(:job).permit(:id, :title, :salary, :description, :apply_description, :language, :premium, :company_id, company_attributes: [:name, :logo, :description, :city, :state, :country, :email]
  end
end

models/job.rb

class Job < ActiveRecord::Base
  accepts_nested_attributes_for :company
  validates :company, presence: true
  ...
end

你应该得到如下内容:

  • 新鲜加载:

  • 选择 'New Company' 选项后':