How to create nested form in Ruby on Rails? - ruby-on-rails

I have following arragement
The Pizza model, to create a list of pizzas that can be ordered by customers, also gets associated with order, so to indicate which pizza has been ordered.
class Pizza < ActiveRecord::Base
has_many :pizza_orders
has_many :orders, :through => :pizza_orders
has_and_belongs_to_many :toppings
end
Option model, to create a list of options that can be associated with certain pizzas, also gets associated with the join table for each pizza order, to specify which pizza has the topping ordered.
class Topping < ActiveRecord::Base
has_and_belongs_to_many :pizzas
has_and_belongs_to_many :pizza_orders
end
The join table for pizza and topping, this is needed because without it, you can not specify which toppings can or can not be ordered with a pizza. After all, having peperoni topping listed to a vegetarian pizza might offend someone.
class PizzasToppings < ActiveRecord::Base
belongs_to :pizza
belongs_to :topping
end
The order model, this just holds all the join tables together.
class Order < ActiveRecord::Base
has_many :pizza_orders
has_many :pizzas, :through => :pizza_orders
end
The join table between pizza and order, this many to many is a has many through, and not a has and belongs to many since in Rails you cannot directly manipulate HBATM join tables (as far as I have tried), and you need to be able to because of the options relation ship.
class PizzaOrder < ActiveRecord::Base
belongs_to :pizza
belongs_to :order
has_and_belongs_to_many :toppings
end
The join table to indicate which toppings have been chosen for a particular pizza in a order.
class PizzaOrdersToppings < ActiveRecord::Base
belongs_to :pizza_orders
belongs_to :topping
end
Then I have an admin page to create and associate the Pizzas and toppings.
But I don't know how to create the orders form. The user should be able to add a pizza and select one or many toppings which are already created

Its a bit old screencast Nested model form part 1 made by ryan bates but i hope it helps you , also there is a revised version of this screencast.

Sorry I was late to respond.
Okay, haven't tested this, but hope it gets you the idea. In order for it to work, this sample relies on,
simple_form
the ryan bates dynamic nested form
I have to apologize, this answer is lacking a large part of it, you need to re-render the link_to_add_fields part every time you change the <%= f.association :pizzas %> value so that the hidden field that contains the toppings match the pizza that has been selected.
Sorry I couldn't get you completly through, but I hope this points you in the right direction.
_form.html.erb
<%= simple_form #order do |f| %>
<%= f.simple_fields_for :pizza_orders do |pizza_orders_fields| %>
<%= f.association :pizzas %>
<%= render partial: "pizza_order_fields", locals: {f: pizza_orders_fields}%>
<%= link_to_add_fields "Add", f, :pizza_orders %>
<% end %>
<% end %>
pizza_order_fields.html.erb would look like
<fieldset>
<%= f.hidden_field :_destroy %>
<%= link_to "Delete", '#', class: "remove_fields btn btn-danger" %>
<%= f.association toppings_pizza_orders, collection: f.object.pizza.toppings %>
</fieldset>

Related

Display rails join table field

So I am making an edit page that can edit animals and the owners to that animal. There is a join table involved which contains what Animal belongs to what Owner.
More precisely, Say you have:
<% form_for :animal, url: animal_path(#edit_animal), method: :patch do |edit| %>
... animal labels and fields to edit go here ...
<%= edit.fields_for :owners do |owner| %>
<%= owner.label :name, "Name" %>
<%= owner.text_field :name %>
<%end%>
<%=edit.submit 'Submit'%>
<%end%>
Model Associations:
AnimalOwner < ApplicationRecord
belongs_to :animal
belongs_to :owner
Owner < ApplicationRecord
has_many :animal_owners
has_many :animals, :through => :animal_owners
Animal < ApplicationRecord
has_many :animal_owners
has_many :owners, :through => :animal_owners
Basically, I am not sure if I am doing the form correctly for join tables. I also wanted to be able to display the data currently saved in the database using :value, but what how I would do that for a join table?
<%= owner.text_field :name, :value => what_goes_here? %>
If you are doing the Rails way, you don't need to mention the value for existing database data.
<%= owner.text_field :name%>
This should populate the data to above given field. Also its always better to use a single for for both "new" and "edit" methods. And for "edit" you can also use "PUT" as method type.
To use the field_for tag, you will also need to tell your Animal model that it accepts_nested_attributes_for :owners. This will allow the nested params to be massed assigned to the Animal instance.

Using has_many :through with fields_for and checkboxes to create associations

That title's a mouthful.
So I have something like this:
class Company < ActiveRecord::Base
has_many :company_partner_associations
has_many :partners, through: :company_partner_associations
end
class CompanyPartnerAssociation
belongs_to :company
belongs_to :partner
end
class Partner
has_many :company_partner_associations
has_many :companies, through: :company_partner_associations
end
And on a company form, i'm trying to make a list of all Partners with a checkbox next to them. If I check one, it creates association. If I uncheck it destroys.
<%= f.fields_for :company_partner_associations, Partner.all do |p| %>
<%= f.check_box :partner_id %>
<% end %>
fails because the object getting passed is a Partner, so getting undefined partner_id on Partner
I'm sure there's a nifty solution out there! Thank you!
Do this:
<%= f.collection_check_boxes :partner_ids, Partner.all, :id, :name %>
No fields_for.
This will have to be accompanied in the controller with the following params:
params.require(:company).permit(:company, :params, partner_ids: [])
This should set the partner_ids in your #company model.
With HABTM, you can declare associative data by populating the "collection_singular_ids" method; HMT has the same method appended with the has_many relation:
Although this will replace the current associated objects, it is much simpler than calling f.fields_for - especially for picking partners.
--
You can also use collection_check_boxes which is meant for this purpose :)
Not totally sure this is the problem here, but I think it could be that your controller is just not permitting the array of partner ids. So in your company_partner_params in your company controller needs to permit something like partner_attributes: [:id]. The syntax might not be perfectly correct there, but if that's something you're missing, you should look around for that.
This is what I think the form should look like:
<%= form_for #company do |f| %>
<%= f.fields_for :partners, Partner.all do |partner| %>
...
<% end %>
<% end %>

Multiple checkboxes for a has_many through not saving

I am not sure why my checkboxes for a has_many through are not saving. This is a rather complex form (An online application for a language summer program) so in addition to regular applicant information, I am collecting attributes of a LanguageBackgroundAndInterest model using a fields_for. Part of these attributes are the books that the applicant used to learn the language. The code looks like this:
<%= f.fields_for :language_background_and_interest do |builder| %>
<div class="field">
<%= hidden_field_tag "language_background_and_interest[book_ids][]" %>
<% Book.all.each do |book| %>
<br><%= check_box_tag "language_background_and_interest[book_ids][]", book.id %>
<%= book.name.humanize %>
<% end %>
</div>
<% end %>
Both the language_background_and_interest and books are joined together using a has_many_through like so:
class LanguageBackgroundAndInterest < ActiveRecord::Base
attr_accessible :book_ids
has_many :language_background_books
has_many :books, through: :language_background_books
end
class Book < ActiveRecord::Base
attr_accessible :name, :publisher
has_many :language_background_books
has_many :language_background_and_interests, through: :language_background_books
end
# Join Table
class LanguageBackgroundBook < ActiveRecord::Base
attr_accessible :language_background_and_interest_id, :book_id
belongs_to :language_background_and_interest
belongs_to :book
end
I am not sure why the books from the checkboxes don't get assigned to the appropriate background model. Any ideas?
PS: Granted, this design is rather ambiguous (Why not make books belong to an applicant?), but I currently want to put up a prototype and I am also constrained by a dubious requirement. So I need this working.
I ended up reviewing my model design and simplified it. I also switched to Simple Form to ease up working with my complex forms.

Has_many :through in Rails 3 - with an extra ID to be set in the joining model

I have put together a diagram to help explain the issue: http://i.imgur.com/ZnN1X.png
Basically, on my "New Employee" form, I currently have a input field for employee name, and a select box that lists all companies. If I select a company and hit go, it creates a new record in "employment". So far, so good.
My issue is that when selecting a company, it also needs to set the type in the "employment" model, which links to the "employment type" model. Ideally, so that I can have 2 different types of employment - but both list the same companies.
Thanks in advance, any help would be greatly appreciated!
Not sure I complete understand your question, but I'll take a shot at it.
Employee Model:
has_many :employments, :dependent => :destroy
has_many :companies; :through=>employments
has_many :employment_types, :through=>employments
Company Model:
has_many :employments
has_many :employees; :through=>employments
has_many :employment_types, :through=>employments
Employment Type Model:
has_many :employments
has_many :companies; :through=>employments
has_many :employees; :through=>employments
Employment Model:
belongs_to :employee
belongs_to :company
belongs_to :employment_type
View code:
<%= form_for #employee do |f| %>
<%= f.text_field :name %>
<% 2.times do %>
<%= f.fields_for :employments, #employee.employments.build do |employment_fields| %>
<%= f.select :company_id, options_from_collection_for_select(Company.all, 'id', 'name') %>
<%= f.select :employment_type_id, options_from_collection_for_select(EmploymentType.all, 'id', 'name') %>
<% end %>
<% end %>
<% end %>
In your diagram you have the ID fields as non standard (model_id), rails typically prefers these to just be id. But you can over ride the default primary key by adding this to each model:
set_primary_key <symbol representing primary key>

has_many :through formtastic multi-select field

I'm trying to set up a many to many relationship using the has_many :through method and then use a multi-select field to setup the relationships. I'm following this tutorial:
http://asciicasts.com/episodes/185-formtastic-part-2
However for some reason the form displays a strange hex number and it changes each page refresh, I'm not exactly sure what I'm doing wrong. Below is my model/view code.
company.rb
has_many :classifications
has_many :sics, :through => :classifications
sic.rb
has_many :classifications
has_many :companies, :through => :classifications
classification.rb
belongs_to :company
belongs_to :sic
_form.html.erb
<% semantic_form_for #company do |f| %>
<% f.inputs do %>
<%= f.input :company %>
<%= f.input :sics %>
<% end %>
<%= f.buttons %>
<% end %>
Also here is the the form looks like it's showing the correct number of entries for the field but it is clearly not showing the correct name for the relationship.
SIC Multi-Select http://web9.twitpic.com/img/103694166-98ad71116216d3d1b12dd77690b36248.4bf6ca20-full.jpg
What you are seeing in the to_s method of an ActiveRecord::Base object. The hex number is the memory location which would be different each request.
After poking around the Formastic code, it looks for methods from a predefined list to find the text to display.
Make sure your Sic model has a field (or method) in this list to_label, display_name, full_name, name, title, username, login, value, to_s that returns the text you want.

Resources