在Rails 5.1中,如何使用一个表单来更新两个表?

时间:2017-10-31 20:57:13

标签: ruby-on-rails

我一直试图让一个表单更新Ruby on Rails中的两个表。我在这里做了相当详尽的搜索,我发现指南有点令人困惑。我找到的最接近的答案是:

Ruby on Rails Saving in two tables from one form

我大部分都复制了这个答案,但我还是无法让它发挥作用。以下是相关的代码:

模型 - 我有两个模型,供应商和帐户。每个供应商应该有一个帐户。

class Supplier < ApplicationRecord
  has_one :account
  accepts_nested_attributes_for :account
end

class Account < ApplicationRecord
  belongs_to :supplier
end

表格 - 不确定这是否完全正确

<h2>Please enter a supplier</h2>
  <%= form_for(@supplier) do |form| %>

<p>
  <%= form.label :name %><br>
  <%= form.text_field :name %>
</p>

<p>
 <%= form.fields_for :account do |f| %>
 <%= f.label :account_number %><br>
 <%= f.text_field :account_number %>
</p>

<p>
 <%= form.submit %>
</p>
 <% end %>
<% end %>

最后,SuppliersController

class SuppliersController < ApplicationController

  def index
    @suppliers = Supplier.all
  end

  def new
    @supplier = Supplier.new
    @supplier = build_account
  end

  def create
    @supplier = suppliers.build(supplier_params)

    if @supplier.save
      redirect_to suppliers_path
    else
      redirect_to root_path
    end
  end

  private

  def supplier_params
    params.require(:supplier).permit(:name, account_attributes: 
                                             [:account_number])
  end

end

我在SuppliersController的新操作的第二行收到未定义的方法错误,我不知道原因。

调试SupplierController中的创建操作的打印输出:

开始POST&#34; /供应商&#34;对于127.0.0.1在2017-11-03 08:25:25 - 0600 由SuppliersController处理#create as HTML   参数:{&#34; utf8&#34; =&gt;&#34;✓&#34;,&#34; authenticity_token&#34; =&gt;&#34; KEqvPgjrYmuBux3qWCQJLAkSLQ4z1ns4HsK2P9sWlhVegpjhik / JoWT3vlL / kP42XpU8adllOaqSA16izYJ0SA ==&#34; ,&#34;供应商&#34; =&gt; {&#34;名称&#34; =&gt;&#34;&#34;,&#34; account_attributes&#34; =&gt; {&#34; account_number& #34; =&gt;&#34;&#34;}},&#34;提交&#34; =&gt;&#34;创建供应商&#34;}

(0.1ms)开始交易

SQL(0.5ms)INSERT INTO&#34;供应商&#34; (&#34; created_at&#34;,&#34; updated_at&#34;,&#34; name&#34;)VALUES(?,?,?)[[&#34; created_at&#34;,&#34 ; 2017-11-03 14:25:25.388933"],[&#34; updated_at&#34;,&#34; 2017-11-03 14:25:25.388933&#34;],[&# 34;姓名&#34;,&#34; Bob&#34;]]

(0.6ms)提交事务    (0.0ms)开始交易

供应商负荷(1.0ms)SELECT&#34;供应商&#34;。* FROM&#34;供应商&#34;在哪里&#34;供应商&#34;。&#34; id&#34; =?限制? [[&#34; id&#34;,6],[&#34; LIMIT&#34;,1]]   SQL(0.3ms)INSERT INTO&#34; accounts&#34; (&#34; created_at&#34;,&#34; updated_at&#34;,&#34; account_number&#34;,&#34; supplier_id&#34;)VALUES(?,?,?,?)[[& #34; created_at&#34;,&#34; 2017-11-03 14:25:25.424367"],[&#34; updated_at&#34;,&#34; 2017-11-03 14:25 :25.424367&#34;],[&#34; account_number&#34;,&#34; 456456456&#34;],[&#34; supplier_id&#34;,6]]

(0.6ms)提交事务

供应商:#Supplier id:6,created_at:&#34; 2017-11-03 14:25:25&#34;,updated_at:&#34; 2017-11-03 14:25:25&#34; ,姓名:&#34; Bob&#34;

帐户:#Account id:1,created_at:&#34; 2017-11-03 14:25:25&#34;,updated_at:&#34; 2017-11-03 14:25:25&#34; ,account_number:&#34; 456456456&#34;,supplier_id:6

(0.0ms)开始交易    (0.0ms)提交事务

重定向到http://localhost:3000/suppliers 完成302发现在51ms(ActiveRecord:4.6ms)

2 个答案:

答案 0 :(得分:0)

您的问题是build_account是供应商对象上的方法。当你有你的代码时,它正在尝试运行build_account,就像它是SuppliersController上的方法一样

因此,您应该尝试将您的控制器方法更新为:

def new
  @supplier = Supplier.new
  @account = @supplier.build_account
end

这会针对您刚刚实例化的供应商对象调用build_account,将结果作为实例化的帐户对象返回,与其所属的供应商实例相关联。

build_account方法是通过您在供应商模型中定义的关联生成的,您在其中说has_one :account。这里的文档http://guides.rubyonrails.org/association_basics.html#has-one-association-reference描述了以这种方式创建的所有方法。

修改

关于创建操作的问题,应该更新控制器。在评论中我们调试了模型,它们看起来像我们希望的那样工作,所以一旦更新,控制器应该工作:

def create
  # Created a Supplier, but not yet persisted.
  @supplier = Supplier.new(supplier_params)

  # Persists the supplier, giving him an id, which can then be used
  # through implicit autosave functionality to take the nested params
  # to build the associated account. All of these operations are wrapped
  # in a single DB transaction, ensuring nothing is left dangling if
  # there is a validation failure
  if @supplier.save
    redirect_to suppliers_path
  else
    redirect_to root_path
  end
end

基于关联自动保存功能,应根据从表单传递的嵌套参数,在保存供应商时自动创建新的关联记录(帐户),而无需添加任何其他代码来显式处理此。此处记录了更多自动保存选项:http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html

答案 1 :(得分:-1)

来自指南,本节

4.1.1 Methods Added by belongs_to

Book模型的每个实例都将包含以下方法:

正如我的朋友指出的那样,我假设

@supplier = Supplier.build_account // wrong
@account = @supplier.build_account 

是正确的