I am creating a hierarchical list of values (id, code, name, parent_id) for which the code is the business key. This means that when a user wants to attach a value to a parent, he fills in a parent_code field, and before save the model associates the parent value id. The value.rb model has a virtual attribute: parent_code, and the following before_save action:
class Value < ActiveRecord::Base
extend CsvHelper
# This virtual attribute allows user to ignore parent value id
attr_accessor :parent_code
### scope
# Value is linked to a list which belongs to the correct scope
### before filter
before_save :set_parent_id # user only inputs parent code
### validation
validates :code, presence: true
validates :name, presence: true
belongs_to :values_list
has_many :subs, :class_name => "Value", :foreign_key => :parent_id
belongs_to :superior, :class_name => "Value", :foreign_key => :parent_id
### private functions definitions
private
### before filters
def set_parent_id
self.level = 1
if not self.parent_code.blank?
#parent = Value.where("code = ? and values_list_id = ?", self.parent_code, self.values_list_id).first
self.parent_id = #parent.id
self.level = #parent.level.next
end
end
end
This model is used as nested object of a values_list model. This works fine at creation, and produces the expected result.
But when editing a record, the parent_code attribute is by no way initialized, and thus now shown in the input field. Here is the nested form:
<table class="table table-striped table-condensed">
<tr align="left">
<th></th>
<% if #values_list.is_hierarchical %>
<th> <%= t('ParentCode') %> </th>
<th> <%= t('Level') %> </th>
<% end %>
<th> <%= t('Code') %> </th>
<th> <%= t('Value') %> </th>
<th> <%= t('Description') %> </th>
</tr>
<%= f.nested_fields_for :values, #values_list.values.order(:code), wrapper_tag: 'tr' do |value| %>
<td><%= value.remove_nested_fields_link {image_tag("remove.png")} %></td>
<% if #values_list.is_hierarchical %>
<td><%= value.text_field :parent_code, ***# code to initialise #*** %> </td>
<td><%= value.text_field :level, disabled: true %> </td>
<% end %>
<td><%= value.text_field :code %> </td>
<td><%= value.text_field :name %> </td>
<td><%= value.text_field :description %> </td>
<% end %>
</table>
How can I initialise the input field with myvalue.superior.code ?
Thanks a lot!
You could access the form object that you're using in your f.nested_fields_for and set the value that way probably.
<%= f.nested_fields_for :values, #values_list.values.order(:code), wrapper_tag: 'tr' do |value| %>
...
<td><%= value.text_field :parent_code, value: value.object.superior.code %> </td>
<td><%= value.text_field :level, disabled: true %> </td>
...
Related
Lets say I have three objects/models; years, cars, and parts. Now, I have cars belong_to parts. The thought on this was that a part may be part of many cars but a car has only one of that part at a given time. and years has_many cars through car_years. I have successfully nested the cars form in the years form. However, when I try to nest the parts form in the cars form and create a new year I get cannot mass assign protected: parts. But, I can create a new car and it will successfully create the new part. I would like to know if I am on the right track or should I be looking elsewhere to solve this. I got the idea from rails cast #196.
Year model
class Year < ActiveRecord::Base
attr_accessible :year, :cars_attributes
has_many :car_years
has_many :cars, :through => :machine_years
accepts_nested_attributes_for :car_years,
:reject_if => lambda { |a| a[:num_cars].blank? },
:allow_destroy => true
accepts_nested_attributes_for :cars,
:reject_if => lambda { |a| a[:doors].blank? },
:allow_destroy => true
end
Car model
class Machine < ActiveRecord::Base
attr_accessible ..., :part_id, :part_attributes
has_many :car_years
has_many :years, :through => :car_years
belongs_to :part
accepts_nested_attributes_for :car_years
accepts_nested_attributes_for :years
accepts_nested_attributes_for :part,
:reject_if => lambda { |a| a[:name].blank? }
end
Parts Model
class Part < ActiveRecord::Base
attr_accessible :desc, :name
has_many :machines
end
Year_form View
<%= form_for(#year) do |f| %>
<% if #year.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#year.errors.count, "error") %> prohibited this year from being saved:</h2>
<ul>
<% #year.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :year %><br />
<%= f.date_select :year, :start_year => 1940, :end_year => Time.now.year, :discard_day => true, :discard_mon th => true %>
</div>
<h3>Cars</h3>
<div>
<%= f.fields_for :cars do |builder| %>
<%= render 'car_fields', :f => builder %>
<% end %>
<p><%= link_to_add_fields "Add Car", f, :cars %></p>
</div>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Car_fields.html.erb
<div class="field">
<h3>New Car</h3>
<table>
<tbody>
<tr>
<th><%= f.label :name %></th>
<th><%= f.label :model %></th>
<th><%= f.label :part_id %></th>
</tr>
<tr>
<td><%= f.text_field :name %></td>
<td><%= f.text_field :model %></td>
<td>
<%= f.fields_for :part do |builder| %>
<%= render "cars/parts_fields", :f => builder %>
<% end %>
</td>
<td><%= f.number_field :memory_id %></td>
</tr>
<tr>
<th><%= f.label :install_dt, "Install Date" %></th>
<th></th>
<th><%= f.label :production_dt, "Production Date" %></th>
<th></th>
<th><%= f.label :remove_dt, "Remove Date" %></th>
</tr>
<tr>
<td><%= f.date_select :install_dt, :start_year => 1940, :end_year => Time.now.year %></td>
<td></td>
<td><%= f.date_select :production_dt, :start_year => 1940, :end_year => Time.now.year %></td>
<td></td>
<td><%= f.date_select :remove_dt, :start_year => 1940, :end_year => Time.now.year %></td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<th><%= f.label :history %></th>
<th></th>
<th><%= f.label :design %></th>
<th></th>
<th><%= f.label :notes %></th>
</tr>
<tr>
<td><%= f.text_area :history, :rows => 4 %></td>
<td></td>
<td><%= f.text_area :design, :rows => 4 %></td>
<td></td>
<td><%= f.text_area :notes, :rows => 4 %></td>
</tr>
</tbody>
</table>
<div style="padding: 2px;">
<%= f.label :image %><br />
<%= f.text_field :image %>
</div>
<%= link_to_function "remove", "remove_fields(this)" %>
</div>
cars/part_fields.html.erb
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %><br />
<%= f.label :desc %><br />
<%= f.text_area :desc, :rows => 3 %>
</div>
Hard to tell without seeing any of you code. However the following error cannot mass assign protected: parts means that you should add attr_accessible :parts to your model in order to be able to do something like this:
a_part = Part.new
another_part = Part.new
Car.new(parts: [a_part, another_part])
Otherwise, without it, you would have to do:
c = Car.new
c.parts << a_part
c.parts << another_part
OK, so the solution was in another post:
Getting fields_for and accepts_nested_attributes_for to work with a belongs_to relationship
In the car_fields form I needed to call
<%= f.fields_for :part_attributes do |builder| %>
not
<% =f.fields_for :parts do |builder| %>
However, now when I look at the year edit screen the part fields are empty, but the part_type does exist
I have a Customer and Invoice Model. A customer has many invoices and an invoice belongs_to a customer. An invoice has many invoice items and Invoice items belong to an invoice
class Customer < ActiveRecord::Base
attr_accessible :billing_address, :customer_currency, :email, :first_name, :last_name, :mobile, :name, :payment_terms, :phase_type, :pays_vat
validates_presence_of :first_name, :last_name, :mobile, :billing_address, :payment_terms, :phase_type, :customer_currency
has_many :invoices
validates :email,
:presence => true,
:uniqueness => true,
:email_format => true
validates :name, :mobile, :presence => true, :uniqueness => true
end
Invoice Model
class Invoice < ActiveRecord::Base
belongs_to :customer
attr_accessible :approved_by, :due_date, :invoice_date, :terms, :customer_id, :customer
validates :invoice_date, presence: true
validates :due_date, presence: true
validates :customer, presence: true
has_many :invoice_items
accepts_nested_attributes_for :invoice_items
end
Invoice Items model
class InvoiceItem < ActiveRecord::Base
belongs_to :invoice
attr_accessible :amount, :description, :rate, :tax_amount
end
I have created an index page for Invoices where I want to list all invoices with their corresponding items however, the challenge I am having is how to access the amount in invoice items and display it in the index page
app/views/index.html.erb
<div class="row">
<div class="span12">
<table class="table table-striped">
<thead>
<tr>
<th>Invoice ID </th>
<th>Customer Name </th>
<th>Invoice Date </th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<% #invoices.each do |invoice| %>
<tr>
<td><%= link_to invoice.id, invoice_path(invoice) %></td>
<td><%= invoice.customer.name %></td>
<td><%= invoice.invoice_date %></td>
<td><%= invoice.invoice_items.amount %></td>
</tr>
<% end %>
</tbody>
</table>
<div class="form actions">
<p>
<%= link_to t('.new', :default => t("helpers.links.new")),
new_invoice_path, :class => 'btn btn-primary' %>
</p>
</div>
</div>
</div>
invoice.invoice_items.amount does not return that amount from Invoice_items for that invoice. Any ideas?
Below is my Invoices_controller index method
class InvoicesController < ApplicationController
before_filter :authenticate_user!
def index
#invoices = Invoice.includes(:customer, :invoice_items).all
end
end
You can get amount of any elements using
invoice.invoice_items.count
or
invoice.invoice_items.size
invoice.invoice_items.first.amount
iterate on invoice_items too, inside #invoices iterator
<% #invoices.each do |invoice| %>
<tr>
<td><%= link_to invoice.id, invoice_path(invoice) %></td>
<td><%= invoice.customer.name %></td>
<td><%= invoice.invoice_date %></td>
<% invoice.invoice_items.each do |invoice_item| %>
<td><%= invoice_item.rate %></td>
<td><%= invoice_item.amount %></td>
</tr>
<% end %>
adjust the table
I'm using rails 3.2.
I have many to many type of models.
Is there a way to set a "value" of a model to field_for.label?
Here's what I want to do.
Client model
class Client < ActiveRecord::Base
attr_accessible :name, :renewal_month1, :renewal_month10, :renewal_month11, :renewal_month12, :renewal_month2, :renewal_month3, :renewal_month4, :renewal_month5, :renewal_month6, :renewal_month7, :renewal_month8, :renewal_month9, :sales_person_id, :usable, :user_id, :licenses_attributes
has_many :licenses, :dependent => :destroy
has_many :systems, :through => :licenses
accepts_nested_attributes_for :licenses
end
License model
class License < ActiveRecord::Base
attr_accessible :amount, :client_id, :system_id
belongs_to :client
belongs_to :system
def system_name
self.system.name
end
end
System model
class System < ActiveRecord::Base
attr_accessible :name, :sort
has_many :clients
has_many :licenses
has_many :clients, :through => :licenses
end
In client controller I built license object for all system.
def new
#client = Client.new
#title = "New Client"
System.all.each do |system|
#client.licenses.build(:system_id => system.id)
end
respond_to do |format|
format.html # new.html.erb
format.json { render json: #client }
end
end
In _form.html.erb I use fieds_for for licenses
<%= f.fields_for :licenses do |ff| %>
<tr>
<td><%= ff.label :system_id %></td>
</td>
<td> <%= ff.number_field :amount %>
<%= ff.hidden_field :system_id %>
<%= ff.hidden_field :system_name %>
</td>
</tr>
<% end %>
Result I get is this
<tr>
<td><label for="client_licenses_attributes_0_system_id">System</label></td>
</td>
<td> <input id="client_licenses_attributes_0_amount" name="client[licenses_attributes][0][amount]" type="number" value="10" />
<input id="client_licenses_attributes_0_system_id" name="client[licenses_attributes][0][system_id]" type="hidden" value="1" />
<input id="client_licenses_attributes_0_system_name" name="client[licenses_attributes][0][system_name]" type="hidden" value="SYSTEMNAME" />
</td>
</tr>
I want the label to look like this.
<td><label for="client_licenses_attributes_0_system_id">SYSTEMNAME</label></td>
SYSTEMNAME is the value of the model SYSTEM.
I have a virtual attribute in LICENSE model defined as system_name.
I was able to get SYSTEMNAME in hidden_field so I think models and controllers are fine.
I just couldn't find out how to set the value of a model to label.
Why can't you use the following?
<%= ff.label :system_name %>
I think the next code should work as well
<%= ff.label :amount, ff.object.system_name %>
I can't test this, but I hope it will generate
<label for="client_licenses_attributes_0_amount">SYSTEMNAME</label>
Note, that it creates a label for amount field, so that when the user click on it, amount field will be focused.
Have you tried adding system_name to the label
<%= f.fields_for :licenses do |ff| %>
<tr>
<td><%= ff.label :system_id, :system_name %></td>
<td> <%= ff.number_field :amount %>
<%= ff.hidden_field :system_id %>
<%= ff.hidden_field :system_name %>
</td>
</tr>
<% end %>
Using Ruby 1.8.6 & Rails 1.2.
Models: Job, JobExtraStop:
class JobExtraStop < ActiveRecord::Base
belongs_to :job
end
class Job < ActiveRecord::Base
belongs_to :lead, :foreign_key => :id
has_one :quote, :foreign_key => :id
has_many :credit_card
has_many :job_extra_stops
end
Code from View:
Main View
<%= render_partial 'jobs/job_address_stop_fields', "stop" => stop, "index"=> index %>
Partial that is called:
<span class="jasf" id="lead_form_adrr_fields">
<% fields_for "job_extra_stop[#{index}]", stop do |extra_stop_form| %>
<tr>
<td><%= extra_stop_form.text_field :st_num, :size => 2%></td>
<td><%= extra_stop_form.text_field :st_name, :size => 15%></td>
<td><%= extra_stop_form.text_field :apt_num, :size => 2%></td>
<td><%= extra_stop_form.text_field :city, :size => 9%></td>
<td><%= extra_stop_form.text_field :zip, :size => 5%></td>
<td><%= extra_stop_form.select(:state,( [[ "Select State", "" ]] + State::NAMES)) %>
</td>
<td><%= extra_stop_form.text_field :floor, :size => 2%></td>
<td> <%= extra_stop_form.text_field :elevator, :size => 1%></td>
<td> <%= extra_stop_form.text_field :action_type, :size => 5%></td>
<td> <%= extra_stop_form.select(:location_type, ([["pick-up"],["drop-off"],["extra_stop"]] )) %></td>
<td> <%= extra_stop_form.text_field :note, :size => 10%></td>
<td>^ / v</td>
<td> <%= link_to_function "Remove", "$(this).up('.jasf').remove()" %></td>
</tr>
<% end %>
</span>
Error:
Undefined Local Variable or method index
Don't know what I am doing wrong.
You are not using the correct syntax for passing local variables to your partial, check here for the correct syntax http://api.rubyonrails.org/classes/ActionView/PartialRenderer.html
I am struggling to get the nested form rendered with belongs_to association.
I was expecting the address fields in the "_form.html.erb" (below) to be rendered correct, but apparently it is not, and i just cant wrap my head around it to figure why!
Rails version: 3.09
here is the code.
Model:
Store.rb
class Store < ActiveRecord::Base
has_and_belongs_to_many :products
belongs_to :store_address, :foreign_key => "address_id", :class_name => "Address"
......
end
Address doesn't have any reference to Store model (it is independent)
Controller
stores_controller.rb
def new
#store = Store.new
#store.build_store_address
respond_with(#store)
end
View
new.html.erb
<% form_for(#store, :url => collection_url) do |f| %>
<%= render :partial => "form", :locals => { :f => f } %>
<p class="form-buttons">
<%= button t('continue') %>
</p>
<% end %>
_form.html.erb
<%=t(:store_name)%> : <%= text_field :store, :name %>
<%=t(:store_admin_email)%> : <%= text_field :store, :admin_email %>
<fieldset>
<legend><label><%=t(:address)%></label></legend>
<% f.fields_for :store_address do |address_form| %>
<table>
<tbody><tr>
<td width="200"><label><%=t(:line_1)%></label></td><td>
<%= address_form.text_area :address1, :rows => 2%>
</td>
</tr>
<tr>
<td><label><%=t(:line_2)%></label></td><td>
<%= address_form.text_area :address2, :rows => 2 %>
</td>
</tr>
<tr>
<td><label><%=t(:city)%></label></td><td>
<%= address_form.text_field :city %>
</td>
</tr>
.......
This renders the store name. but nothing on the address side. please help!
I think you missed an = at <% f.fields_for .... It should be <%= f.fields_for... .
This has happened to me so often in the past, missing this one thing, and then wondering why the nested form would not render.