Trouble about nested attributes form - ruby-on-rails

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

Related

Rails 5 trouble with saving a nested fields_for .. error message <xxx> must exist

I have the following models:
class Person < ApplicationRecord
has_many :interests, dependent: :destroy
accepts_nested_attributes_for :interests
validates_presence_of :email
validates_inclusion_of :gender, :in => %w(M F), message: "Gender can only be in M or F"
has_secure_password
def name
"#{first_name} #{last_name}"
end
def interests_concatenated
interests.map { |i| i.interest }.join(", ")
end
end
class Interest < ApplicationRecord
belongs_to :person
end
My controller is as follows:
class PeopleController < ApplicationController
def index
#person = Person.all
end
def new
#person = Person.new
#person.interests.build
end
def create
#person = Person.new(people_params)
if #person.save
session[:user_id] = #person.id
redirect_to(people_path)
else
flash = "Email or gender can't be blank!"
render 'new'
end
end
private
def people_params
params.require(:person).permit(:email, :first_name, :last_name, :gender, :password,:password_confirmation, interests_attributes: [:hobby])
end
end
My form is as follows:
<%= form_for #person do |f| %>
<p>
<%= f.label :email %> <br>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :first_name %> <br>
<%= f.text_field :first_name %>
</p>
<p>
<%= f.label :last_name %> <br>
<%= f.text_field :last_name %>
</p>
<p>
<%= f.label :gender %> <br>
<%= f.label(:gender_male, "Male") %>
<%= f.radio_button(:gender, "M") %> <br>
<%= f.label(:gender_female, "Female") %>
<%= f.radio_button(:gender, "F") %> <br>
</p>
<p>
<%= f.label :password %> <br>
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %> <br>
<%= f.password_field :password_confirmation %>
</p>
<p>
<%= f.fields_for :interests do |i| %>
<%= i.label :hobby %>
<%= i.text_field :hobby %>
<% end %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Here is the byebug console log when I run it:
Very stumped why it's not working. Could it be something to do with the parameters?
Here is the log file when I submit the form:
Instead of:
#interests = #person.interests.new
try
#interests = #person.interests.build
new creates a fresh, clean, completely empty new object... but build is the special Rails association method that will fill it with appropriate defaults (like, eg the right person_id)
I found a working solution by adding this in my interests model:
class Interest < ApplicationRecord
belongs_to :person, **optional: true**
end
Since #person fails to save each time, the biggest clue was in the error message "Interest person must exist", I found this StackOverflow solution to be helpful. Also this blog post on why this is needed was helpful in shedding light on the issue.
Thanks to everyone that weighed in on it!

ActiveModel::MassAssignmentSecurity::Error with nested attributes

Hi im trying to create a relation one-to-many in my rails app.
Fist i create my models
class Produto < ActiveRecord::Base
attr_accessible :compra, :descricao, :estoque, :venda
has_many :precos
accepts_nested_attributes_for :precos
end
class Preco < ActiveRecord::Base
attr_accessible :compra_decimal, :produto_id, :venda_decimal
belongs_to :produto
end
Then i created my controller
class ProdutosController < ApplicationController
def new
#produto = Produto.new
#produto.precos.build
end
def create
#produto = Produto.new(params[:produto])
if #produto.save?
redirect_to produtos_path
end
end
end
After this i created my .html.erb pages:
_form
<%= form_for #produto do |f| %>
<p>
<%= f.label :descricao %><br/>
<%= f.text_field :descricao %>
</p>
<p>
<%= f.label :compra %><br/>
<%= f.text_field :compra %>
</p>
<p>
<%= f.label :venda %><br/>
<%= f.text_field :venda %>
</p>
<p>
<%= f.label :estoque %><br/>
<%= f.text_field :estoque %>
</p>
<%= f.fields_for :precos do |builder| %>
<%= render "precos", :f => builder %>
<% end %>
<p><%= f.submit %></p>
<% end %>
_precos
<p>
<%= f.label :venda_decimal %><br/>
<%= f.text_field :venda_decimal %>
</p>
<p>
<%= f.label :compra_decimal %><br/>
<%= f.text_field :compra_decimal %>
</p>
new
<%= render "form" %>
then, when i submit the form this error appears:
ActiveModel::MassAssignmentSecurity::Error in ProdutosController#create
Can't mass-assign protected attributes: precos_attributes
does anyone have any idea about it?
Just change your model:
class Produto < ActiveRecord::Base
attr_accessible :compra, :descricao, :estoque, :venda, :precos_attributes
has_many :precos
accepts_nested_attributes_for :precos
end

Rails deep nested/non nested form

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.

Problem with Association on rails 3

View
<%= form_for #product, :url => admin_products_path do |f| %>
<div>
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div>
<%= f.label :description %>
<%= f.text_area :description, :rows => 7 %>
</div>
<%= f.fields_for :address do |a| %>
<p><%= a.label "Address One" %><br />
<%= a.text_field :address_one %></p>
<p><%= a.label "Address Two" %><br />
<%= a.text_field :address_two %></p>
<p><%= a.label :city %><br />
<%= a.text_field :city %></p>
<p><%= a.label :postcode %><br />
<%= a.text_field :postcode %></p>
<p><%= a.label :country %><br />
<%= a.select :country_id, Country.active.collect {|p| [ p.printable_name, p.id ] } %></p>
<% end %>
<% end %>
Controller
def create
#product = Product.new(params[:product])
if #product.save
flash[:notice] = 'Product was successfully created.'
render 'show'
else
render 'new'
end
end
model
class Product < ActiveRecord::Base
has_one :address, :as => :addressable
end
but when save data it show issue:
Address(#93165130) expected,got ActiveSupport::HashWithIndifferentAccess(#79365750)
Please help me solved this problem
Try if adding accepts_nested_attributes_for :address solves this.
accepts_nested_attributes_for :address
if not work then try also adding along with accepts_nested_attributes_for :address
attr_accessor :address

Validation always fails on all fields

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.

Resources