2

すべてのデータを入力した後、データ入力フォーム(複雑なフォーム)を保存しようとするとこのメッセージが表示されるように、どこが間違っているのかを理解するのを手伝ってください。

私は次のように5つのモデルを持っています:

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'

部分的な_fields:

<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 ::AssociationTypeMisMatch。Client(#xxxxxx)が必要です、Array(#xxxxxx)を取得しました。

もう1つの問題は、コントラクトモデルに「accepts_nested_attributes_for:codelines」を含めると、「units_alloc」属性がフォームから消えることです。

これらの2つの質問について、ヘルプやガイダンスをいただければ幸いです。私は複雑なフォームを読み、「複雑なフォーム」のレールキャストを見て、関連付けに関するRailsガイドとaccepts_nested_attributes_forメソッドに関するAPIドキュメントを読んで再読しました。明らかに、これらの概念についての私の理解は、これらの問題を解決するために必要な完全な理解に達していないので、助けを求めています。

app / controllers/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

Contracts_controller.rbのcreateアクションの最初の行として「raiseparams[:contract].to_s」を追加しました。出力は次のとおりです。

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 = @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がすべての関連付けを参照するのは正しいですか?」です。私が持っているもう1つの質問は、「クライアント、コード、およびコードラインのレコードを作成するためにform_helperを使用する必要がありますか?」です。私がこれを尋ねる理由は、contracts_controllerにあるビルドアクションにもかかわらず、それはまだnilであるように見えるからです。2番目の質問に対する答えが「はい」の場合、form_helperの作成をガイドするリソースを教えていただけますか?RailsGuidesをチェックしています。

ありがとう。

アップデート2

私は輪になって行きました、私は私のcontracts_controllerの新しいアクションを次のように変更しました:

def new
  @contract = Contract.new

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

また、契約モデルを次のように戻しました。

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

最後に、ビューの部分的な_fields.html.hamlで、コードラインに関連するセクションを削除しました。

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

そして今、私のパラメータには必要な「clients_attributes」と「codes_attributes」があり、その結果、フォームは適切なテーブルに保存されます。私はまだいくつかの問題を抱えています。つまり、コードラインの余分な属性、'units_alloc'などですが、状況は良くなっています。

4

2 に答える 2

2

さて、あなたの問題はあなたのフォームがセットアップされる方法にあります。

contractモデルは、のネストされた属性を受け入れることができますが、、のネストされた属性をclientlines受け入れようとしています。clientscode

これを行うには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

ClientLinesはの所有者でcodesありclients、ネストされた属性を受け入れる必要がある関係である ため、ここでの混乱を理解していると思いますが、それは正しくありません。

を使用すると、とhas_many :codes, :through => :clientlinesの間にファーストクラスの関連付けが設定されます。したがって、フォームで新しいものを作成する場合は、モデルで言う必要があります。ContractCodecodescontractaccepts_nested_attributes_for :codesContract

お役に立てれば。

したがって、パラメータの最後の投稿に関して、問題は:codes:clientsです。モデルにaccepts_nested_attributes_for :codesaccepts_nested_attributes_for :clientsコードがある場合、これは問題なく機能するはずです。Contract

ここに問題があります。クライアントまたはコードを適切にビルドするには、それらの親オブジェクトもビルドする必要があります。したがって、コントローラーは次のようになります。

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またはを表示する必要があります。:codesparams:clients_attributes:codes_attributes

私は本当にそれがそれをするべきだと思います。

于 2012-03-01T21:25:28.100 に答える
0

最初の答えは大きな助けになりましたが、それでも解決策にたどり着くことができませんでした。私は、 nested_formsをデバッグして、このサイトで最後までやり遂げた解決策を見つけました。

これは、has_many:throughアソシエーションを使用している場合は、joinモデルまたはそれに近いものに基づいてnested_formを作成する必要があることを読んだ9番目の箇条書きです。

いくつかのコードをあちこちでリファクタリングしてテストをすばやく実行しました。これで、コントローラーに正しいパラメーターを提供する実行可能なネストされたフォームができました。コントローラーはそれを正しく処理し、コードラインテーブルには1つのレコードしかありません。

于 2012-04-06T22:04:23.270 に答える