I'm trying to create a form handling 4 models at once with 2 nested pairs... Got an error: You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.
Is there someone to guide me with this one? For your info I'm using rails 3.0. and I need to handle the 4 models in the same view... Thanks a lot for your help because this one is driving me nuts for days :)
Here is the controller's code:
def new
#pinvoice = Pinvoice.new
#journal = Journal.new
#compte = Compte.find(:all)
if Journal.last.nil?
then
#internal = 'Pinv1'
else
#internal = 'Pinv' + (Journal.last.id + 1).to_s
end
1.times {#pinvoice.pinvlines.build}
4.times {#journal.lignes.build}
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #pinvoice }
end
end
The models code:
class Pinvoice < ActiveRecord::Base
has_many :pinvlines, :dependent => :destroy
accepts_nested_attributes_for :pinvlines
end
class Pinvline < ActiveRecord::Base
belongs_to :pinvoice
belongs_to :compte
belongs_to :pinvoice
end
class Ligne < ActiveRecord::Base
belongs_to :journal
belongs_to :compte
attr_accessor :should_destroy
def should_destroy?
should_destroy.to_i == 1
end
end
class Journal < ActiveRecord::Base
has_many :lignes, :dependent => :destroy
accepts_nested_attributes_for :lignes, :reject_if => lambda { |a| a[:montant].to_s == "0"}
attr_accessor :taux
attr_accessor :compte_tva
validates_presence_of :date
validates_presence_of :texte
validates_presence_of :montant_HTVA
validates_presence_of :banque
validates_presence_of :compte
before_update :delete_lignes
def delete_lignes
#lignes.each do |l|
if l.new_record?
l.save
else
l.destroy
end
end
end
end
and the big one the form:
<%= javascript_include_tag 'javascript_pinvlines_fields_new' %>
<%= form_for #pinvoice do |f| %>
<% if #pinvoice.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#pinvoice.errors.count, "error") %> prohibited this pinvoice from being saved:</h2>
<ul>
<% #pinvoice.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :internal %>
<%= f.text_field :internal, :value => #internal %><br />
<%= f.label :contact %>
<%= f.text_field :contact, :id => 'test' %>
<%= f.label :date_facture %>
<%= f.date_select :date_facture %>
<%= f.label :montant_total %>
<%= f.text_field :montant_total %>
</p>
<h2>Details</h2>
<%= f.fields_for :pinvlines do |builder| %>
<%= render "pinvline_fields", :f => builder %>
<%end%>
<p><%= link_to_add_fields "Ajouter une ligne", f, :pinvlines%></p>
<h2>Jounal</h2>
<%= fields_for #journal do |j| %>
<%= j.label :date %><br />
<%= j.text_field :date, :size => 10 %> <i> au format YYYY-MM-DD </i><br />
<%= j.label :texte %><br />
<%= j.text_field :texte%><br />
<%= j.label :banque %><br />
<%= j.text_field :banque %><br />
<%= j.label :montant_hors_tva %><br />
<%= j.text_field :montant_HTVA%><br />
<%= j.label :tva_id %><br />
<%= j.text_field :tva_id %><br />
<%= j.label :taux %><br />
<%= j.text_field :taux %><br />
<%= j.label :compte_tva %><br />
<%= j.text_field :compte_tva %><br />
<%= j.label :montant_TVA %><br />
<%= j.text_field :montant_TVA%><br />
<%= j.label :montant %><br />
<%= j.text_field :montant %><br />
<%= j.label :compte %><br />
<%= j.text_field :compte %><br />
<%= j.label :internal %><br />
<%= j.text_field :internal, :value => #internal%><br />
<%= j.label :source %><br />
<%= j.text_field :source%>
<br />
<h2>Lignes</h2>
<div class='container'>
<div class="duplicate">
<%= j.fields_for :lignes do |j| %>
<%= j.label :date %>
<%= j.text_field :date, :size=> 8 %>
<%= j.label :compte_id %>
<%= j.text_field :compte_id, :size=> 8 %>
<%= j.label :montant %>
<%= j.text_field :montant, :size=> 8 %>
<%= j.label :debit %>
<%= j.text_field :debit, :size=> 8 %>
<%= j.label :credit %>
<%= j.text_field :credit, :size=> 8 %>
<br />
<% end %>
</div>
</div>
<%end%>
<p><%= f.submit %></p>
<% end %>
At the end I've found a way to handle this with a call back at the model level.
Related
I have 2 models setup like so:
class Campaign < ApplicationRecord
has_many :cities
belongs_to :user
end
class City < ApplicationRecord
belongs_to :campaign
end
Controller:
def new
#campaign = current_user.campaigns.build
#cities = #campaign.cities
end
I would like users to be able to create and edit cities directly from the campaign page. I am not sure how to do this, here is my attempt. How do I access city.name? :name is the param key for #campaign
<%= form_for #campaign do |f| %>
<%= f.label "Name" %>
<br />
<%= f.text_field :name %>
<br /> <br />
<%= f.label "Titles" %>
<br />
<%= f.text_area :titles, cols: 80, rows: 20 %>
<br /> <br />
<%= f.label "Sentences" %>
<br />
<%= f.text_area :sentences, cols: 80, rows: 20 %>
<br /> <br />
<%= f.label "Keywords" %>
<br />
<%= f.text_area :keywords, cols: 80, rows: 20 %>
<br /> <br />
<% if #cities.count > 0 %>
<h2>Cities</h2>
<% for city in #cities %>
<%= f.label "City name:" %>
<br />
<%= f.text_area :name, cols: 80, rows: 20 %>
<% end %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
I was able to do this with:
<% if #cities.count > 0 %>
<h2>Cities</h2>
<% for city in #cities %>
<%= form_for city do |f| %>
<%= f.text_area :name, cols: 20, rows: 1 %>
<%= f.text_area :phone_number, cols: 20, rows: 1 %>
<%= f.text_area :zip_code, cols: 20, rows: 1 %><%= f.submit "Submit" %>
<% end %>
<% end %>
<% end %>
This is my first question. I hope you can help me. I have two models.
class Cliente < ActiveRecord::Base
attr_accessible :cedula, :direccion, :nombres, :telefono
validates :cedula, :direccion, :nombres, :telefono, :presence => true
validates :cedula, :uniqueness => { :message => "Cedula ya en uso" }
has_many :facturas
class Factura < ActiveRecord::Base
attr_accessible :cliente_attributes, :iva, :numero, :subtotal, :total, :created_at
belongs_to :cliente
accepts_nested_attributes_for :cliente
I want in the facturas#new view can create or edit Cliente. If exists update or if not exists create. I am using nested attributes. If exists I uses javascript to fill text fields. If not exists I fill text field and save when Factura save. This is facturas#new view.
<h1>Nueva Factura</h1>
<%= form_for #factura do |f| %>
<% if #factura.errors.any? %>
<h2>Errores:</h2>
<ul>
<% #factura.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<p>
<div class = "contenedor_factura">
<%= f.label :numero %><br />
<%= f.number_field :numero %><br />
<%= f.label :fecha %><br />
<%= f.date_select :created_at %><br />
</div>
<div class = "contenedor_cliente">
<%= f.fields_for #cliente do |builder| %>
<%= builder.label :cedula, "Cédula" %>
<%= builder.text_field :cedula %>
<%= builder.label :nombres, "Nombres" %>
<%= builder.text_field :nombres %>
<%= builder.label :direccion, "Dirección" %><br />
<%= builder.text_field :direccion %>
<%= builder.label :telefono, "Teléfono" %><br />
<%= builder.text_field :telefono %>
<%= builder.hidden_field :id%>
<% end %>
</div>
<div class = "contenedor_productos">
</div>
<%= f.label :subtotal %><br />
<%= f.text_field :subtotal %>
<br />
<%= f.label :iva %><br />
<%= f.text_field :iva %>
</p>
<p>
<%= f.submit "Agregar Nueva Factura" %>
</p>
<% end %>
When the Cliente is new i have no problem, it saves, but if Cliente exists i have this message
ActiveRecord::RecordNotFound in FacturasController#create
Couldn't find Cliente with ID=6 for Factura with ID=
What is my problem?
EDIT:
This is my FacturasController
def new
#factura = Factura.new
#cliente = #factura.build_cliente
end
def create
#factura = Factura.new(params[:factura])
if #factura.save
redirect_to facturas_path, :notice => "Factura Guardada"
else
render "new"
end
end
I'm not sure if nested_attrubes handles already created models. So we can just not depend on it.
This should work
def create
cliente_attrs = params[:factura].delete :cliente
#cliente = cliente_attrs[:id].present? ? Cliente.find(cliente_attrs[:id]) : User.create(user_attrs)
#factura = cliente.facturas.build(params[:factura])
if #factura.save
redirect_to facturas_path, :notice => "Factura Guardada"
else
render "new"
end
end
You can now delete the line accepts_nested_attributes_for :cliente
I followed this screencast to make a nested model form.
http://railscasts.com/episodes/196-nested-model-form-part-1
Now, I am trying my application to include such a nested model form but I received a argument error (wrong number of arguments(0 for 1)).
I can't seem to figure out where I went wrong and would like to seek some advice on what I could try out and why some an error might have occurred.
The error happens on this line in the Subject Model.
has_many :lessons, :dependent => destroy
The other relevant codes:
Subjects Controller:
def new
#subject = Subject.new
#3 times one for lecture one for lab one for tut.
3.times{#subject.lessons.build}
respond_to do |format|
format.html # new.html.erb
format.json { render json: #subject }
format.js
end
end
Subject Model
class Subject < ActiveRecord::Base
has_many :lessons, :dependent => destroy
attr_accessible :lesson_attributes, :acad_unit, :cohort_size, :discipline, :remarks, :subject_code, :subject_name, :year_of_study
accepts_nested_attributes_for :lessons, :reject_if => lambda { |a| a[:lesson_type].blank? }, :allow_destroy => true
end
Lesson Model
class Lesson < ActiveRecord::Base
belongs_to :subject
attr_accessible :frequency, :lesson_type, :no_of_lesson, :possible_venues
end
_form.html.erb
<%= form_for(#subject,:remote=>true) do |f| %>
<% if #subject.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#subject.errors.count, "error") %> prohibited this subject from being saved:</h2>
<ul>
<% #subject.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :subject_code %><br />
<%= f.text_field :subject_code %>
</div>
<div class="field">
<%= f.label :subject_name %><br />
<%= f.text_field :subject_name %>
</div>
<div class="field">
<%= f.label :year_of_study %><br />
<%= f.text_field :year_of_study %>
</div>
<div class="field">
<%= f.label :discipline %><br />
<%= f.text_field :discipline %>
</div>
<div class="field">
<%= f.label :acad_unit %><br />
<%= f.text_field :acad_unit %>
</div>
<div class="field">
<%= f.label :cohort_size %><br />
<%= f.text_field :cohort_size %>
</div>
<div class="field">
<%= f.label :remarks %><br />
<%= f.text_field :remarks %>
</div>
<ol>
<%= f.fields_for :lessons do |builder| %>
<%= render "lesson_fields", :f => builder %>
<% end %>
</ol>
<% end %>
_lesson_fields.html.erb
<p>
<div class="field">
<%= f.label :lesson_type %><br />
<%= f.text_field :lesson_type %>
</div>
<div class="field">
<%= f.label :no_of_lesson %><br />
<%= f.text_field :no_of_lesson %>
</div>
<div class="field">
<%= f.label :frequency %><br />
<%= f.text_field :frequency %>
</div>
<div class="field">
<%= f.label :possible_venues %><br />
<%= f.text_field :possible_venues %>
</div>
</p>
I guess you wanted :
has_many :lessons, :dependent => :destroy
?
Here you'll find a nice discussion on topic.
I am still having problems with nested forms. Here is my form code:
<%= form_for #account do |f| %>
<%= f.label :account_type %><br />
<%= f.text_field :account_type %><br />
<%= f.fields_for :organizations do |builder| %>
<%= builder.label :name %><br />
<%= builder.text_field :name %><br />
<%= builder.label :website %><br />
<%= builder.text_field :website %><br />
<%= f.fields_for :locations do |builder| %>
<%= builder.label :phone %><br />
<%= builder.text_field :phone %><br />
<%= builder.label :toll_free_phone %><br />
<%= builder.text_field :toll_free_phone %><br />
<%= builder.label :fax %><br />
<%= builder.text_field :fax %><br />
<% end %>
<% end %>
<%= f.submit "Add account" %>
<% end %>
The Account model:
class Account < ActiveRecord::Base
has_many :organizations
accepts_nested_attributes_for :organizations
end
The Organization model:
class Organization < ActiveRecord::Base
belongs_to :account
has_many :locations
accepts_nested_attributes_for :locations
end
And the Location model:
class Location < ActiveRecord::Base
belongs_to :organization
end
And lastly, the Accounts Controller:
class AccountsController < ApplicationController
def new
#account = Account.new
organization = #account.organizations.build
organization.locations.build
#header = "Create account"
end
def create
#account = Account.new(params[:account])
if #account.save
#handle success
else
render 'new'
end
end
end
Here is the error I am getting:
ActiveRecord::UnknownAttributeError in AccountsController#create
unknown attribute: locations
Rails.root: C:/Documents and Settings/Corey Quillen/My
Documents/rails_projects/shop_manager
Application Trace | Framework Trace | Full Trace
app/controllers/accounts_controller.rb:12:in `new'
app/controllers/accounts_controller.rb:12:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"xuZLSP+PSjdra3v51nIkJYZeXRM0X88iF135hPlp4sc=",
"account"=>{"account_type"=>"Company",
"organizations_attributes"=>{"0"=>{"name"=>"Atlas",
"website"=>"www.atlas.com"}},
"locations"=>{"phone"=>"555-555-5555",
"toll_free_phone"=>"800-555-5555",
"fax"=>"512-555-5555"}},
"commit"=>"Add account"}
Any help with this will be greatly appreciated. I have been looking at this now for a couple of hours.
You should use new builder in nested form for nested nested form :)) :
<%= form_for #account do |f| %>
<%= f.label :account_type %><br />
<%= f.text_field :account_type %><br />
<%= f.fields_for :organizations do |builder| %>
<%= builder.label :name %><br />
<%= builder.text_field :name %><br />
<%= builder.label :website %><br />
<%= builder.text_field :website %><br />
<%= builder.fields_for :locations do |lb| %>
<%= lb.label :phone %><br />
<%= lb.text_field :phone %><br />
<%= lb.label :toll_free_phone %><br />
<%= lb.text_field :toll_free_phone %><br />
<%= lb.label :fax %><br />
<%= lb.text_field :fax %><br />
<% end %>
<% end %>
<%= f.submit "Add account" %>
<% end %>
An even DRYer solution:
1) in your Gemfile, list nested_form as a dependency.
2) in your models do this:
class Account < ActiveRecord::Base
accepts_nested_attributes_for :organizations
end
class Organization < ActiveRecord::Base
accepts_nested_attributes_for :locations
end
3) create regular forms for Organization under ./app/view/organizations/
and for Location under./app/view/locations/`
4) in your Account form, do this: (it gets pretty short this way!)
<%= nested_form_for #account do |f| %>
<%= f.label :account_type %><br />
<%= f.text_field :account_type %><br />
<%= f.fields_for :organizations %>
<%= f.submit "Add account" %>
<% end %>
5) in your Organization form, do this: (also pretty short)
<%= nested_form_for #organization do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %><br />
<%= f.label :website %><br />
<%= f.text_field :website %><br />
<%= f.fields_for :locations %>
<%= f.submit "Add Organization" %>
<% end %>
Check these RailsCasts:
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
I'm on Rails 3. I have a model called Client that has name, phone and email. My model file looks like this:
class Client < ActiveRecord::Base
belongs_to :salon
belongs_to :address
validates_presence_of :name
validates_presence_of :phone
validates_presence_of :email
accepts_nested_attributes_for :address
attr_accessible :address_attributes
end
As you can see, name, phone and email are all required. When I go to the form where I'm supposed to be able to create a new Client and submit it, all three validations fail, no matter what I put in the fields. Here is my form file:
<%= form_for(#client) do |f| %>
<% if #client.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#client.errors.count, "error") %> prohibited this client from being saved:</h2>
<ul>
<% #client.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :salon_id, :value => Salon.logged_in_salon.id %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :phone %><br />
<%= f.text_field :phone %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<%= f.fields_for :address do |address_form| %>
<div class="field">
<%= address_form.label :line1 %><br />
<%= address_form.text_field :line1 %>
</div>
<div class="field">
<%= address_form.label :line2 %><br />
<%= address_form.text_field :line2 %>
</div>
<div class="field">
<%= address_form.label :city %><br />
<%= address_form.text_field :city %>
</div>
<div class="field">
<%= address_form.label :state_id %><br />
<%= select("client[address]", "state_id", State.all.collect {|s| [ s.name, s.id ] }) %>
</div>
<div class="field">
<%= address_form.label :zip %><br />
<%= address_form.text_field :zip %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Here's my create action:
def create
#client = Client.new(params[:client])
respond_to do |format|
if #client.save
format.html { redirect_to(#client, :notice => 'Client was successfully created.') }
format.xml { render :xml => #client, :status => :created, :location => #client }
else
format.html { render :action => "new" }
format.xml { render :xml => #client.errors, :status => :unprocessable_entity }
end
end
end
Any idea why this is happening?
It's because you set :address_attributes as the only accessible attribute. Change
attr_accessible :address_attributes
to
attr_accessible :address_attributes, :name, :phone, :email
or don't use mass assignment.