ruby-on-rails-3 - Rails 3.2.1嵌套形式和accepts_nested_attributes_for返回: :Client(xxxxx) expected,得到数组(xxxxx)”

标签 ruby-on-rails-3 nested-forms nested-attributes model-associations

请帮助我理解我哪里出了问题,以至于当我输入所有数据后尝试保存数据输入表单(复杂表单)时收到此消息?

我有以下五个模型:

class Contract < AR::Base
  has_many :clientlines
  has_many :codelines
  has_many :clients, :through => :clientlines
  has_many :codes, :through => :codelines

  accepts_nested_attributes_for :clientlines
end

class Clientline < AR::Base
  belongs_to :contract
  belongs_to :client

  accepts_nested_attributes_for :contract
end

class Client < AR::Base
  has_many :clientlines
  has_many :contracts, :through => :clientlines
end

class Codeline < AR::Base
  belongs_to :contract
  belongs_to :code
  units_alloc

  accepts_nested_attributes_for :code
end

class Code < AR::Base
  has_many :codelines
  has_many :contracts, :through => :codelines
end

我使用以下文章作为我的设计来源:

http://rubysource.com/complex-rails-forms-with-nested-attributes/

在我的 app/controller/contracts_controller.rb 中,我有以下内容:

def new
  @contract = Contract.new
  4.times { @contract.codes.build }
  4.times { @contract.codelines.build }
end

def create
  @contract = Contract.new(params[:contract])
  if @contract.save
    flash[:success] = "New Contract has been saved"
    redirect_to @contract # this redirects to the contract show page
  else
    @title = "You have some errors"
    render 'new'
  end
end
.
.
.
end

我将复杂的形式组合如下:

- provide(:title, 'Add Contract')
%h2 New Contract
=form_for(@contract) do |f|
  =render 'shared/contract_error_messages', object: f.object
  =render 'fields', f:  f
  .actions
    = f.submit "Save", class: 'save strong round'

部分字段:

<fieldset><legend>Enter Contract Details</legend>
.field
  = f.label :name, "AuthNum"
  %br/
  = f.text_field  :authnum, :size => 10, :class => "ui-state-default"
.field
  = f.label :name, "Start Date"
  %br/
  = f.text_field  :st_date, :size => 12, :class => "ui-state-default"
.field
  = f.label :name, "End Date"
  %br/
  = f.text_field  :end_date, :size => 12, :class => "ui-state-default"
</fieldset>
<fieldset><legend>Enter Client Details</legend>
= f.fields_for :clients do |ff|
  .field
    = ff.label :name, "First Name"
    %br/
    = ff.text_field :f_name, :size => 15, :class => "ui-state-default"
  .field
    = ff.label :name, "MI"
    %br/
    = ff.text_field :mi, :size => 3, :class => "ui-state-default"
  .field
     = ff.label :name, "Last Name"
     %br/
     = ff.text_field :l_name, :size => 15, :class => "ui-state-default"
  .field
     = ff.label :name, "Birth Date"
     %br/
     = ff.text_field :birth_date, :size => 12, :class => "ui-state-default"
  .field
     = ff.label :name, "Address1"
     %br/
     = ff.text_field :address1, :size => 25, :class => "ui-state-default"
  .field
     = ff.label :name, "Address2"
     %br/
     = ff.text_field :address2, :size => 25, :class => "ui-state-default"
  .field
     = ff.label :name, "City"
     %br/
     = ff.text_field :city, :size => 15, :class => "ui-state-default"
  .field
     = ff.label :name, "ZipCode"
     %br/
     = ff.text_field :zip_code, :size => 10, :class => "ui-state-default"
  .field
     = ff.label :name, "State"
     %br/
     = ff.text_field :state, :size => 15, :class => "ui-state-default"
  .field
     = ff.label :name, "MedicareNum"
     %br/
     = ff.text_field :medicarenum, :size => 20, :class => "ui-state-default"
  .field
     = ff.label :name, "MedicaidNum"
     %br/
     = ff.text_field :medicaidnum, :size => 20, :class => "ui-state-default"
  .field
     = ff.label :name, "MemberNum"
     %br/
     = ff.text_field :membernum, :size => 20, :class => "ui-state-default"
  .field
     = ff.label :name, "SocSerCareMgr"
     %br/
     = ff.text_field :socsercaremgr, :size => 20, :class => "ui-state-default"
  .field
     = ff.label :name, "SSCM_Ph"
     %br/
     = ff.text_field :sscm_ph, :size => 15, :class => "ui-state-default"
  .field
     = ff.label :name, "NurseCareMgr"
     %br/
     = ff.text_field :nursecaremgr, :size => 20, :class => "ui-state-default"
  .field
     = ff.label :name, "NCM_Ph"
     %br/
     = ff.text_field :ncm_ph, :size => 15, :class => "ui-state-default"
  .field
     = ff.label :name, "EmergencyContact"
     %br/
     = ff.text_field :emergencycontact, :size => 20, :class => "ui-state-default"
  .field
     = ff.label :name, "EC_Ph"
     %br/
     = ff.text_field :ec_ph, :size => 15, :class => "ui-state-default"
  .field
     = ff.label :name, "PrimaryCarePhy"
     %br/
     = ff.text_field :primarycarephy, :size => 20, :class => "ui-state-default"
  .field
     = ff.label :name, "PCPhy_Ph"
     %br/
     = ff.text_field :pcphy_ph, :size => 15, :class => "ui-state-default"
</fieldset>
<fieldset><legend>Enter Billing Code Details</legend>
= f.fields_for :codes do |ff|
  .field
    = ff.label :name, "Code Name"
    %br/
    = ff.text_field :code_name, :size => 15, :class => "ui-state-default"
  .field
    = ff.label :name, "Status"
    %br/
    = ff.text_field :status, :size => 10, :class => "ui-state-default"
  .field
    = ff.label :name, "Description"
    %br/
    = ff.text_field :description, :size => 25, :class => "ui-state-default"
= f.fields_for :codelines do |ff|
  .field
    = ff.label :name, "Units Alloc"
    %br/
    = ff.text_field :units_alloc, :precision => 6, :scale => 2, :size => 10, :class => 
    "ui-state-default"
</fieldset>

我的第一个也是迫在眉睫的问题是,一旦我在表单上输入了所有数据,然后按下“保存”按钮,我会得到以下信息:

ContractsController#Create 中的 ActiveRecord::关联类型不匹配。 预期客户端(#xxxxxx),得到数组(#xxxxxx)。

另一个问题是,如果我在合约模型中包含“accepts_nested_attributes_for :codelines”,则“units_alloc”属性将从我的表单中消失。

对于这两个问题的任何帮助或指导将不胜感激。我花了一些时间阅读复杂表单,观看“复杂表单”railcasts,并且阅读并重新阅读了关于关联的 Rails 指南以及关于 Accepts_nested_attributes_for 方法的 API 文档。显然我对这些概念的理解还没有达到解决这些问题所需的完全理解,因此我寻求帮助。

更新 应用程序/ Controller /contracts_controller.rb

class ContractsController < ApplicationController

def index
  @contracts = Contract.paginate(page: params[:page])
end

def show
  @contract = Contract.find(params[:id])
end

def new
  @contract = Contract.new
  @contract.codes.build
  @contract.codelines.build
  @contract.clients.build
end

def create
  raise params[:contract].to_s ------ **this is line #19**
  @contract = Contract.new(params[:contract])
  if @contract.save
    flash[:success] = "New Contract has been saved"
    redirect_to @contract # this redirects to the contract show page
  else
    @title = "You have some errors"
    render 'new'
  end
end

def edit
  @contract = Contract.find(param[:id])
end

def update
  if @contract.update_attributes(params[:contract])
    flash[:success] = "Contract Profile updated"
    redirect_to @contract
  else
    render 'edit'
  end
end
end

我将“raise params[:contract].to_s”添加为contracts_controller.rb 中创建操作的第一行,输出如下:

RuntimeError in ContractsController#create

{"authnum"=>"700900", "st_date"=>"04/03/2012", "end_date"=>"06/29/2012", "clients"=> 
{"f_name"=>"Lefty", "mi"=>"L", "l_name"=>"Right", "birth_date"=>"07/18/1979", 
"address1"=>"54 Frosty Lane", "address2"=>"", "city"=>"Frave", "zip_code"=>"54806",
"state"=>"WI", "medicarenum"=>"789987456", "medicaidnum"=>"931579135", 
"membernum"=>"890333-3", "socsercaremgr"=>"Caring Serving",
"sscm_ph"=>"1-444-444-4444", "nursecaremgr"=>"Caring Nurse", 
"ncm_ph"=>"1-555-555-5555", "emergencycontact"=>"Quick Response", 
"ec_ph"=>"1-666-666-6666", "primarycarephy"=>"This One", "pcphy_ph"=>"1-777-777-7777"},
"codes"=>{"code_name"=>"S-5463", "status"=>"Active", "description"=>"Transition from
sch to mkt"}, "codelines"=>{"units_alloc"=>"80.00"}}

Rails.root: /home/tom/rails_projects/tracking
Application Trace | Framework Trace | Full Trace

app/controllers/contracts_controller.rb:19:in `create'

Request

Parameters:

{"utf8"=>"✓",
"authenticity_token"=>"/i21h2vwzuDPjIrCXzYEIAg41FnMxfGdCQQggjqcZjY=",
"contract"=>{"authnum"=>"700900",
"st_date"=>"04/03/2012",
"end_date"=>"06/29/2012",
"clients"=>{"f_name"=>"Lefty",
"mi"=>"L",
"l_name"=>"Right",
"birth_date"=>"07/18/1979",
"address1"=>"54 Frosty Lane",
"address2"=>"",
"city"=>"Frave",
"zip_code"=>"54806",
"state"=>"WI",
"medicarenum"=>"789987456",
"medicaidnum"=>"931579135",
"membernum"=>"890333-3",
"socsercaremgr"=>"Caring Serving",
"sscm_ph"=>"1-444-444-4444",
"nursecaremgr"=>"Caring Nurse",
"ncm_ph"=>"1-555-555-5555",
"emergencycontact"=>"Quick Response",
"ec_ph"=>"1-666-666-6666",
"primarycarephy"=>"This One",
"pcphy_ph"=>"1-777-777-7777"},
"codes"=>{"code_name"=>"S-5463",
"status"=>"Active",
"description"=>"Transition from sch to mkt"},
"codelines"=>{"units_alloc"=>"80.00"}},
"commit"=>"Save"}

更新1

我将contracts_controller新操作更改为:

def new
  @contract = Contract.new

通过合约构建codelines对象,然后通过codelines对象构建代码

  codelines = @contract.codelines.build
  codelines.codes.build

通过合约构建clientlines对象,然后通过clientlines对象构建客户端

  clientlines = @contract.clientlines.build
  clientlines.clients.build
end

我还通过添加 Accepts_nested_attributes_for :clientlines, :codelines 以及添加 attr_accessor 行来更改我的合约模型。

class Contract < ActiveRecord::Base
  has_many :clientlines
  has_many :codelines
  has_many :clients, :through => :clientlines
  has_many :codes, :through => :codelines

  accepts_nested_attributes_for :clients
  accepts_nested_attributes_for :codes
  accepts_nested_attributes_for :clientlines
  accepts_nested_attributes_for :codelines

  attr_accessor :codes, :clients, :clientlines, :codelines
end

我现在在我的参数中有nested_attribute_writers 和关联名称,但现在我的错误已更改为:

NoMethodError in ContractsController#new

undefined method `build' for nil:NilClass

现在的问题是,“让 attr_accessor 引用所有关联是否正确?” 我的另一个问题是,“我是否必须使用 form_helper 来为客户端、代码和代码线创建记录?”我问这个问题的原因是,尽管我在contracts_controller中进行了构建操作,但它似乎仍然为零。 如果第二个问题的答案是肯定的,您能否指导我找到一些可以指导我构建 form_helper 的资源?我正在检查 RailsGuides。

谢谢。

更新2

我一直在兜圈子,我将contracts_controller新操作更改为:

def new
  @contract = Contract.new

  @contract.codes.build
  @contract.clients.build
end

我还将契约(Contract)模型更改回:

class Contract < ActiveRecord::Base
  has_many :clientlines
  has_many :codelines
  has_many :clients, :through => :clientlines
  has_many :codes, :through => :codelines

  accepts_nested_attributes_for :clients
  accepts_nested_attributes_for :codes

  attr_accessible :clients_attributes, :codes_attributes etc
end

最后,我删除了 View 部分 _fields.html.haml 中与代码行相关的部分,即:

= f.fields_for :codelines do |ff| and the next four lines

现在我的参数具有必要的“clients_attributes”和“codes_attributes”,因此表单保存到适当的表中。我仍然有一些问题,即代码行中的额外属性、“units_alloc”和其他一些问题,但情况看起来好多了。

最佳答案

好的,所以您的问题在于表单的设置方式。

您的contract模型可以接受 clientlines 的嵌套属性,但是,您正在尝试接受 clients 的嵌套属性, code .

为此,您需要设置 Contract型号如下:

class Contract < AR::Base
  has_many :clientlines
  has_many :codelines
  has_many :clients, :through => :clientlines
  has_many :codes, :through => :codelines

  accepts_nested_attributes_for :codes
  accepts_nested_attributes_for :clients
end

我想我理解你在这里的困惑,因为 ClientLinescodes 的所有者和clients这是您应该接受嵌套属性的关系,但这是不正确的。

一旦您使用has_many :codes, :through => :clientlines您已在 Contract 之间设置了一级关联和Code ,所以如果你想创建新的 codescontract表格,那么你需要说 accepts_nested_attributes_for :codes在你的Contract型号。

希望这有帮助。

因此,关于您上次发布的参数,问题是 :codes:clients 。如果您有accepts_nested_attributes_for :codesaccepts_nested_attributes_for :clients代码在你的 Contract模型,这应该可以正常工作。

问题是,为了正确构建客户端或代码,您还需要构建它们的父对象。所以你的 Controller 应该看起来更像这样:

class ContractsController < ApplicationController
  def new
    @contract = Contract.new

    #Build the codelines object throught the contract, then build the codes through the codelines object
    codelines =  @contract.codelines.build
    codelines.build_code

    # Do the same for the clients
    clientlines = @contract.clientlines.build
    clientlines.build_client
  end

现在,如果您正确执行了此操作,则不会看到 :clients:codes在你的params ,您应该看到 :clients_attributes:codes_attributes .

我真的认为应该这样做。

关于ruby-on-rails-3 - Rails 3.2.1嵌套形式和accepts_nested_attributes_for返回: :Client(xxxxx) expected,得到数组(xxxxx)”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9523944/

相关文章:

ruby-on-rails-3 - 尝试在 Rails 源代码中运行 "rake test"

ruby-on-rails-3 - 设计邀请电子邮件中的自定义消息

ruby-on-rails - Rails 5 - 如何使用自动完成功能将嵌套对象动态添加到表单中

ruby-on-rails - 嵌套形式和一对一关系

ruby-on-rails - 如何使用继承和嵌套属性构建 Rails 表单?

ruby-on-rails - Ruby:是否有更有效的方法将哈希键的子集转换为带下划线的符号?

ruby-on-rails - 为什么 declarative_authorization 会破坏我的 Controller 的功能? - rails 3

javascript - bootsy 编辑器不适用于通过nested_form gem 添加的嵌套属性

ruby-on-rails - 在 rails 中具有嵌套属性的表单

ruby-on-rails - 默认情况下显示嵌套属性的表单字段