Rails 3.2.1 Forma nidificata e ACCECTS_NESTED_ATTRIBUTE_FOR RESTITUZIONE :: client (XXXXX) previsto, ottenuto array (xxxxx) "
-
15-11-2019 - |
Domanda
Aiutami a capire dove sto andando male così tanto che ricevo questo messaggio quando provo a salvare il mio modulo di inserimento dati (modulo complesso) una volta inseriti tutti i dati?
Ho cinque modelli come segue:
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
.
Ho usato il seguente articolo della mia fonte di progettazione:
http://rubysource.com/complex-rails-forms-with-nested-attributes/
.
Nella mia app / controller / contract_controller.rb Ho quanto segue:
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
.
Ho messo insieme la forma complessa come segue:
- 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'
.
i campi parziali:
<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>
.
Il mio primo e il mio problema immediato è che una volta che ho inserito tutti i dati sul modulo e poi ho premuto il pulsante "Salva" ottengo quanto segue:
ACTIVERCORD :: Associazione Typemismatch in ContractScontroller # Crea. Client (#xxxxxx) previsto, ottenuto array (#xxxxxx).
L'altro problema è che se includo 'ACCECTISTS_NESTED_ATTRIBUTE_FOR: CODELINES' nel mio modello di contratto, l'attributo 'unità_alloc' scompare dalla mia forma.
Qualsiasi aiuto o orientamento sarebbe più apprezzato in queste due domande. Ho trascorso un po 'di tempo a leggere su forme complesse, ho guardato le "forme complesse" e ho letto e ho letto e ri-leggere le guide dei binari sulle associazioni e la documentazione API su ACCECTS_Nestato Metodo. Ovviamente la mia comprensione di questi concetti non è aumentata fino alla completa comprensione necessaria per risolvere questi problemi, quindi la mia chiamata per aiuto.
Aggiornamento
app / 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
Ho aggiunto il "Sollevare params [: contratto] .to_s" come prima la prima riga nella mia azione di creazione nel contratto_Controller.rb e la produzione segue:
.
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"}
Aggiornamento 1
Ho cambiato il mio contratto_controller Nuova azione per:
.
def new
@contract = Contract.new
Costruisci l'oggetto Codelines tramite il contratto, quindi crea i codici attraverso l'oggetto Codelines
.
codelines = @contract.codelines.build
codelines.codes.build
Costruisci l'oggetto Clientlines attraverso il contratto, quindi crea i client attraverso l'oggetto Clientlines
.
clientlines = @contract.clientlines.build
clientlines.clients.build
end
Ho anche modificato il mio modello di contratto aggiungendo ACCECTS_NESTED_ATTRIBUTE_FOR: clientlines ,: Codelines e aggiungendo la linea ATTR_Accessore.
.
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
Ora ho nidificato_attribute_writer con nomi di associazione nei miei parametri, ma ora il mio errore è cambiato in:
.
NoMethodError in ContractsController#new
undefined method `build' for nil:NilClass
La domanda ora è: "È corretto avere attr_accessore a fare riferimento a tutte le associazioni?" L'altra domanda che ho è: "Devo usare un form_helper per creare record per clienti, codice e co-line?" La ragione per cui chiedo questo è che sembrerebbe che, nonostante l'azione di costruzione che abbia nel mio contratto_controller sembra che sia ancora nulla. Se la risposta è sì alla seconda domanda puoi indirizzarmi a qualche risorsa che mi guiderebbe nella costruzione di un form_helper? Sto controllando guide.
Grazie.
Aggiorna 2
Sono andato nei circoli, ho cambiato la mia nuova azione di contratti per:
.
def new
@contract = Contract.new
@contract.codes.build
@contract.clients.build
end
Ho anche cambiato il mio modello di contratto per:
.
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
Infine ho rimosso la sezione a mio avviso parziale, _fields.html.haml, che pertativa per le codeline, vale a dire:
.
= f.fields_for :codelines do |ff| and the next four lines
E ora i miei parametri hanno il neccessario "clients_attributes" e "codici_attributes" e come risultato il modulo salva alle tabelle appropriate. Ho ancora alcuni problemi, vale a dire l'attributo extra in CoDeline, 'Unità_Alloc' e alcuni altri, ma le cose sembrano migliori.
Soluzione 2
The first answer was a great help, but it did not get me all the way to the solution. I found a solution, that did take me through to the end at this site, debugging nested_forms.
It is the ninth bullet down where you read that if you are working with a has_many :through association then you need to base your nested_form on the join model or something close to that.
I quickly ran a test by refactoring some code here and there and I now have a workable nested form that serves up the correct params to the controller which in turns processes it correctly and my codelines table now has just one record.
Altri suggerimenti
Ok, so your problem is with the way that your forms are setup up.
Your contract
model can accept nested attributes for clientlines
, however, you are trying to accept nested attributes for clients
, code
.
In order to do this you need to setup your Contract
model as follows:
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
I think I understand your confusion here, since ClientLines
is the owner of codes
and clients
that is the relationship that you should accept nested attributes for, but that is incorrect.
Once you use the has_many :codes, :through => :clientlines
you have setup a first class association between Contract
and Code
, so if you want to create new codes
in a contract
form, then you need to say accepts_nested_attributes_for :codes
in your Contract
model.
Hope this helps.
So in regards to your last posting of the params, the problem is the :codes
and :clients
. If you had the accepts_nested_attributes_for :codes
and accepts_nested_attributes_for :clients
code in your Contract
model, this should work just fine.
Here is the problem, in order to properly build the clients or the codes, you need to also build their parent object. So your controller should look more like this:
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
Now, if you have done this properly, instead of seeing :clients
or :codes
in your params
, you should see :clients_attributes
or :codes_attributes
.
I really think that should do it.