使用Rails 5以一种形式创建记录和依赖记录

时间:2018-02-01 05:31:15

标签: ruby-on-rails

我无法理解这个问题。我有一个模型(发票),belongs_to另一个模型(客户)和客户has_many发票。

因此,没有客户就无法创建发票。我希望能够使用相同的表格同时创建一个发票的客户。

现在我已经拥有它,所以你可以手动打入invoice_id并且一切正常但但对于实际使用该应用程序的人来说这并不理想。

我已经阅读了这篇文章,但我仍然不明白,也不确定这是否仍适用于Rails 5: https://stackoverflow.com/a/3809360/7467341

上述答案仍然是正确的方法吗?有人可以澄清,也许可以给我一些代码试试吗?谢谢!

<%= form_for(invoice) do |f| %>
    <% if invoice.errors.any? %>
        <div id="error_explanation">
            <h2><%= pluralize(invoice.errors.count, "error") %>
                prohibited this invoice from being saved:</h2>

            <ul>
                <% invoice.errors.full_messages.each do |message| %>
                    <li><%= message %></li>
                <% end %>
            </ul>
        </div>
    <% end %>


    <h2>Customer Info</h2>
    <hr>
    <div class="field">
        <%= f.label :customer_id %>
        <%= f.number_field :customer_id %>
    </div>

    <!-- My customer model has more fields that I want to go here (name, address, and phone_number) -->

    [...] other regular invoice fields here...

    <div class="actions">
        <%= f.submit %>
    </div>
<% end %>

4 个答案:

答案 0 :(得分:1)

您可能希望使用:cocoon来创建动态嵌套表单

答案 1 :(得分:1)

有很多不同的库可以帮助解决这类问题。但我会尝试建议一个只适用于Rails的解决方案。

因此,我试图分析你的情况,我猜我们需要解决两个问题。第一个是为现有客户添加发票,第二个是在创建发票的同时创建新客户。在我看来,最直接的做法是在表单中添加两个单独的字段。第一个字段是Select下拉列表,您可以从现有Customers中进行选择,第二个字段是Textfield,如果Select字段中没有匹配项,则输入Customer的名称。

然后逻辑将首先检查下拉列表中是否选择了任何内容,在这种情况下,文本字段中的任何文本都将被忽略。但是,如果从下拉列表中选择了任何内容,那么它将根据文本字段创建客户。

以下是我建议如何实现这一目标:

class Invoice < ActiveRecord::Base

  belongs_to :customer

  validate :customer_id, presence: true

  # A dynamic attribute that is NOT represented by a database column in the Invoice model, but only used for the form
  attr_accessor :customer_name, :customer_address #, plus your other fields

  before_validation on: :create do
    if customer_id.nil? && customer_name.present?
      # Use create! (with !) so that an error is raised if the customer 
      # could not be created which will abort the entire save transaction
      self.customer = Customer.create!(name: customer_name, address: customer_address)
      # Add your other customer attributes above as well
    end
  end

end

然后以你的形式

<%= form_for(invoice) do |f| %>

    <h2>Customer Info</h2>
    <hr>
    <div class="field">
        <%= f.label :customer_id, "Choose existing Customer" %>
        <%= f.select :customer_id, options_from_collection_for_select(Customer.all, :id, :name, invoice.customer_id) %>
    </div>

    <div class="field">
        <%= f.label :customer_name, "... or create a new Customer" %>
        <%= f.text_field :customer_name %>
    </div>

    <div class="field">
        <%= f.label :customer_address, "New customer address" %>
        <%= f.text_field :customer_address %>
    </div>
    <!-- Repeat for all your other Customer attributes -->

    [...] other regular invoice fields here...

    <div class="actions">
        <%= f.submit %>
    </div>
<% end %>

并且不要忘记允许来自Controller Invoice.create(params.permit(:customer_name, :customer_address, ...))的其他参数属性。

当然有一些事情可以提高效率,但我希望这可以展示Rails提供的一些开箱即用的功能来解决这样的情况,我认为它很好如果你对Rails有些新意,请专注于此。

答案 2 :(得分:1)

在这种情况下,您可以使用嵌套属性。 在customer.rb文件中,添加此accepts_nested_attributes_for :invoices

在白名单参数中,添加invoices_attribues: [invoice_fields]以及客户字段。

Check this link用于理解fields_for和嵌套属性。 Check this link了解嵌套属性的工作原理。

答案 3 :(得分:0)

这是您尝试在那里执行的嵌套表单:

  1. Rails Guide,9.2嵌套表格
  2. simple_formcocoon
  3. nested forms on google
  4. Nested Forms Rails