Ruby on Rails : Updating Multiple Models from single view/controller - ruby-on-rails

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

Related

Using cocoon, my has_many through association doesn't get updated or deleted

Using cocoon to build my nested form for a has_many through association. The association gets created, however it doesn't update or remove the associations. The following is my nested form:
edit.html.erb:
<div class="case_contacts-edit-container">
<%= link_to_add_association 'ADD CONTACT', f, :case_contacts, :"data-association-insertion-node" => "tbody#case_contacts_", :"data-association-insertion-method" => "append", class: 'action-button insure pull-right' %>
<table id="info-table3">
<tbody id="case_contacts_">
<tr>
<td class="right">
<strong>Name</strong>
</td>
<td class="right">
<strong>Role</strong>
</td>
<td class="right">
<strong>Note</strong>
</td>
<td>
</td>
</tr>
<%= f.simple_fields_for :case_contacts do |case_contact| %>
<%= render 'case_contact_fields', :f => case_contact %>
<% end %>
</tbody>
</table>
_case_contact_fields.html.erb:
<tr class="nested-fields">
<td>
<%= f.association :contact, :collection => (Contact.all.select(:first_name, :last_name, :email, :company_name, :id).map { |contact| [contact.name_with_company, contact.id] }), :prompt => "Add Contact", :class => 'table-input', :label => false %>
</td>
<td>
<%= f.input :role, collection: Contact::TYPES, :prompt => "Add Role", :class => 'table-input', :label => false %>
</td>
<td>
<%= f.input :note, :prompt => "Add Note", :class => 'table-input', :label => false %>
</td>
<%= f.hidden_field :firm_id, :value => #firm.id %>
<td class="insurance-icon" style="text-align: center;">
<%= link_to_remove_association f, class: 'dark-small remove_case_contacts' do %><span id="remove" class="glyphicon glyphicon-trash" original-title="Remove Contact"></span><% end %>
</td>
</tr>
cases_controller.rb (update method):
#case.assign_attributes(case_params)
#case.save
cases_controller.rb (permitted parms):
def case_params
params.require(:case).permit(:name, :case_number, :docket_number, :description, :case_type, :subtype,
:court, :county, :corporation, :status, :hearing_date, :filed_suit_date, :fee_agreement,
:case_contacts_attributes => [:id, :case_id, :updated_at, :created_at, :firm_id, :role, :contact_id, :note, :_destroy])
end
case.rb (model):
has_many :case_contacts, :dependent => :destroy
has_many :contacts, :through => :case_contacts
accepts_nested_attributes_for :case_contacts, :reject_if => :all_blank, :allow_destroy => :true
contact.rb (model):
has_many :case_contacts, :dependent => :destroy
has_and_belongs_to_many :cases, :join_table => 'case_contacts'
case_contact.rb (joiner model):
belongs_to :affair, class_name: 'Case', :foreign_key => 'case_id'
belongs_to :contact

Rails 4 How to display belongs_to record in a list

so please bear with me :)
group.rb
class Group < ActiveRecord::Base
has_many :categories, dependent: :destroy
validates :name, :presence => true, :uniqueness => { :case_sensitive => false }
validates :content, :presence => true
end
category.rb
class Category < ActiveRecord::Base
belongs_to :group
validates :name, :presence => true, :uniqueness => { :case_sensitive => false }
validates :content, :presence => true
validates :group_id, :presence => true
end
app/views/categories/index.html.erb
<% #categories.each do |category| %>
<tr>
<td><%= category.id %></td>
<td>
<%= link_to category.name, admin_category_path(category) %>
</td>
<td><%= ***[GROUP WHERE CURRENT CATEGORY BELONGS TO]*** %></td>
<td>
<%= link_to admin_category_path(category), class: "btn btn-info btn-xs" do %>
<i class="fa fa-search"></i>
<% end %>
<%= link_to edit_admin_category_path(category), class: "btn btn-primary btn-xs" do %>
<i class="fa fa-pencil"></i>
<% end %>
<%= link_to admin_category_path(category), method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-danger btn-xs" do %>
<i class="fa fa-trash-o"></i>
<% end %>
</td>
</tr>
<% end %>
My question is: how to display a group belongs_to this categories?
It's simple, just write:
<td><%= category.group %></td>
Or
<td><%= category.group.name %></td>
One good idea is to define the function "to_s" for your classes.
For example
group.rb
class Group < ActiveRecord::Base
def to_s
name
end
That way Rails will automatically output the name for the group when printing the group meaning that
<td><%= category.group %></td>
and
<td><%= category.group.name %></td>
Will output the same information.
Use <%= category.group.name %> to display a group belongs_to this categories.

Nested forms in ruby on rails using has_many through and belongs to associations

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

Nested attributes are not updating in rails

I have 3 models:
class DropShipOrderLineItem < ActiveRecord::Base
belongs_to :drop_ship_order
belongs_to :line_item
validates_associated :drop_ship_order
validates_associated :line_item
validates :drop_ship_order_id, :presence => true
validates :line_item_id, :presence => true
attr_accessible :missing
end
class DropShipOrder < ActiveRecord::Base
attr_accessible :line_items, :line_items_attributes, :orders, :order_attributes
belongs_to :retailer
belongs_to :order
belongs_to :shipping_method
has_many :drop_ship_order_line_items
has_many :line_items, :through => :drop_ship_order_line_items
has_many :shipments, :dependent => :destroy
accepts_nested_attributes_for :line_items
accepts_nested_attributes_for :order
accepts_nested_attributes_for :drop_ship_order_line_items
before_create :generate_order_number
scope :by_number, lambda {|number| where("drop_ship_orders.number = ?", number)}
scope :between, lambda {|*dates| where("drop_ship_orders.created_at between ? and ?", dates.first.to_date, dates.last.to_date)}
scope :by_customer, lambda {|customer| joins(:order).joins(:user).where("users.email =?", customer)}
scope :by_state, lambda {|state| where("state = ?", state)}
scope :complete, where("drop_ship_orders.completed_at IS NOT NULL")
scope :incomplete, where("drop+ship_orders.orders.completed_at IS NULL")
make_permalink :field => :number
validates_associated :order
validates_associated :retailer
end
LineItem.class_eval do
has_one :drop_ship_order_line_item, :dependent => :destroy
has_one :drop_ship_order, :through => :drop_ship_order_line_items
accepts_nested_attributes_for :drop_ship_order_line_item
attr_accessible :drop_ship_order_line_item
# def missing
# self.drop_ship_order_line_item.missing
# end
end
View #1:
<div data-hook="admin_order_edit_form">
<div id="order-form-wrapper">
<%= render :partial => 'form', :locals => {:drop_ship_order => #drop_ship_order} %>
</div>
</div>
View form:
<%= form_for(#drop_ship_order, :url => admin_drop_ship_order_path(#drop_ship_order), :html => { :method => :put}) do |f| %>
<%= f.hidden_field :number %>
<table class="index">
<tbody id='line-items'>
<tr data-hook="admin_order_form_line_items_headers">
<th><%= t('item_description') %></th>
<th class="price"><%= t('price') %></th>
<th class="qty"><%= t('qty') %></th>
<th class="total"><span><%= t('total') %></span></th>
<th class="orders-actions" data-hook="admin_order_form_line_items_header_actions"></th>
</tr>
<%= f.fields_for :line_items do |li_form| %>
<%= render :partial => "admin/drop_ship_orders/line_item", :locals => { :f => li_form } %>
<% end %>
</tbody>
<tbody id='subtotal' data-hook="admin_order_form_subtotal">
<tr id="subtotal-row">
<td colspan="3"><b><%= t('subtotal') %>:</b></td>
<td class="total"><span><%= number_to_currency #drop_ship_order.item_total %></span></td>
<td></td>
</tr>
</tbody>
view line_item:
<tr id="<%= dom_id(f.object) %>" data-hook="admin_order_form_line_item_row">
<td width="300"><%=f.object.variant.product.name%> <%= "(" + variant_options(f.object.variant) + ")" unless f.object.variant.option_values.empty? %></td>
<td valign="top" class="price"><%= number_to_currency f.object.price %></td>
<td valign="top" class="qty"><strong><%= f.object.quantity %></strong></td>
<td valign="top" class="total"><%= number_to_currency (f.object.price * f.object.quantity)%></td>
<td data-hook="admin_order_form_line_item_actions">
<!--<input type="checkbox" name="apple" id="apples"/>-->
<%#= f.object.drop_ship_order_line_item.missing %>
<%= f.fields_for :drop_ship_order_line_item do |build|%>
<%= build.check_box :missing, :type => "checkbox" %>
<% end %>
</td>
</tr>
The :missing attribute is not being updated, and I just can't figure out why! Although the checkboxe is correctly being ticked if I manually change the values in my SQL table.
p.s: I just posted the relevant parts of my code.
In your LineItem model change attr_accessible :drop_ship_order_line_item to attr_accessible :drop_ship_order_line_item_attributes.
What is the :type => "checkbox" for in the following code:
<%= build.check_box :missing, :type => "checkbox" %>
The second parameter for the check_box form helper should be the method. I think if you change to the following code, it should work:
<%= build.check_box :missing %>

Ruby: UnknownAttributeError

i have some Orders that can have several Items and these Items have an associated Kind. The Kind can belong to many Items. but i get a "unknown attribute: kinds" in my OrdersController when i hit the submit form button. I use nested forms btw.
Order.rb
class Order < ActiveRecord::Base
validates_presence_of :ref_nr, :total_price
has_many :items, :dependent => :destroy
has_many :kinds, :through => :items
accepts_nested_attributes_for :items
accepts_nested_attributes_for :kinds
validates_associated :items
validates_associated :kinds
end
Item.rb
class Item < ActiveRecord::Base
belongs_to :order
has_one :kind
accepts_nested_attributes_for :kind
validates_associated :kind
end
Kind.rb
class Kind < ActiveRecord::Base
belongs_to :items
end
OrdersController.rb:Create
def create
#order = Order.new(params[:order])
end
new.erb.html
<% form_for #order do |f| %>
<%= f.error_messages %>
<% f.fields_for :items do |builder| %>
<table>
<tr>
<% builder.fields_for :kinds do |m| %>
<td><%= m.collection_select :kind, Kind.find(:all, :order => "created_at DESC"), :id, :name, {:prompt => "Select a Type" }, {:id => "selector", :onchange => "kind_change(this)"} %></td>
<% end %>
<td><%= builder.text_field :amount, :id => "amountField", :onchange => "change_total_price()" %></td>
<td><%= builder.text_field :text, :id => "textField" %></td>
<td><%= builder.text_field :price, :class => "priceField", :onChange => "change_total_price()" %></td>
<td><%= link_to_remove_fields "Remove Item", f %></td>
</tr>
</table>
<% end %>
<p><%= link_to_add_fields "Add Item", f, :items %></p>
<p>
<%= f.label :total_price %><br />
<%= f.text_field :total_price, :class => "priceField", :id => "totalPrice" %>
</p>
<p><%= submit_tag %></p>
<% end %>
i cant see what im missing
You should remove accepts_nested_attributes_for :kinds in Order model and it should be in Item model (as in your code). Then change view here:
...
<% f.fields_for :items do |builder| %>
<table>
<tr>
<% builder.fields_for :kind do |m| %>
...
And I think that you have also mistake in following lines:
<td><%= f.text_field :amount, :id => "amountField", :onchange => "change_total_price()" %></td>
<td><%= f.text_field :text, :id => "textField" %></td>
<td><%= f.text_field :price, :class => "priceField", :onChange => "change_total_price()" %></td>
If fields amount, text and price are associated with Item model, then you should use builder instead of f:
<td><%= builder.text_field :amount, :id => "amountField", :onchange => "change_total_price()" %></td>
<td><%= builder.text_field :text, :id => "textField" %></td>
<td><%= builder.text_field :price, :class => "priceField", :onChange => "change_total_price()" %></td>
EDIT (to answer additional questions from comments):
You should have:
<% f.fields_for :items do |builder| %>
<table>
<tr>
<td><%= builder.collection_select :kind_id, Kind.find(:all, :order => "created_at DESC"), :id, :name, {:prompt => "Select a Type" }, {:id => "selector", :onchange => "kind_change(this)"} %></td>
<td><%= builder.text_field :amount, :id => "amountField", :onchange => "change_total_price()" %></td>
<td><%= builder.text_field :text, :id => "textField" %></td>
<td><%= builder.text_field :price, :class => "priceField", :onChange => "change_total_price()" %></td>
and so on...

Resources