Rails 3: nested form rendered with belongs_to association - ruby-on-rails

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.

Related

Ruby on Rails: Creating new model in nested association with has_many relationship

So I have an issue where a user needs to be able to place an order, each order is made up of one of more pizza_order models. A pizza_order has a polymorphic relationship with a pizza model in that it can either point to an entry in the specials table which has a pre-defined list of toppings, or it can point to an entry in the pizzas table, at which point the user can choose the crust type and toppings.
I had previously solved the issue of trying to create multiple pizza_order entries in one order by using the Cocoon gem, and that works fine. It even works fine when each pizza_order is only associated with an entry from specials table. Once I try to get the custom pizza entry to work things start breaking.
This is what a new order will look like
<%= form_for #order do |f| %>
<%= f.fields_for :pizza_orders do |pi_order| %>
<%= render partial: 'pizza_order_fields', locals: {f: pi_order}%>
<% end%>
<div class="add-field">
<%= link_to_add_association 'Add Pizza', f, :pizza_orders, id: "add_btn", class: "btn btn-primary" %>
</div>
<br/>
<%= f.submit "Place Order", class: "btn btn-primary "%>
<% end %>
Whenever the user pressed 'Add Pizza' this will render a new partial to pick either a specialty, or custom pizza. That form looks like this
<div class="nested-fields">
<fieldset data-role="controlgroup" data-type="horizontal" class="form-inline">
<legend>Specialty Pizzas</legend>
<% #specials.each do |sp| %>
<div class="container">
<%= f.label :pizza_id, sp.get_name_and_cost %>
<%= f.radio_button :pizza_id, sp.id %>
<h5>Crust Type: <%= sp.pizza.crust.name %></h5>
<h5>Toppings:
<% sp.pizza.toppings.each do |top| %>
<%= top.name + (top == sp.pizza.toppings.last ? "" : ",") %>
<% end %>
</h5>
<hr/>
</div>
<% end %>
<div class="container">
<%= f.label "Custom" %>
<%= f.radio_button :pizza_id, "Custom", id: "custom_pizza" %>
<div id="custom_pizza_fields">
<%= f.fields_for :pizza_id do |pi| %>
<%= render partial: 'custom_pizza', locals: {pi: pi} %>
<% end %>
</div>
</div>
</fieldset>
<%= f.label :quantity %>
<%= f.number_field :quantity, class: "number_field" %>
<br/>
<%= link_to_remove_association "Delete", f , id: "delete_btn", class: "btn btn-primary" %>
<hr/>
Finally this renders a partial to create a custom pizza, which looks like this
<h5>Crust Type</h5>
<table class="table">
<tr>
<% Crust.all.each do |crust| %>
<td>
<%= pi.label :crust, crust.name %>
<%= pi.radio_button :crust, crust.id %>
</td>
<% end %>
</tr>
</table>
<h5>Toppings</h5>
<table class="table">
<tr>
<% Topping.all.each do |topping| %>
<td>
<%= pi.label :toppings, topping.get_name_and_cost %>
<%= pi.check_box :toppings %>
</td>
<% end %>
</tr>
</table>
I'm fairly certain the problem is coming from this 2nd fields_for line, which reads <%= f.fields_for :pizza_id do |pi| %>. Unlike the specialty pizza, which already exist in the database, custom pizzas will be created when the user places the order. So I don't think :pizza_id will map to anything at this point.
Another issue is how do I return a collection of Toppings to map to the has_many field in the pizza model? I have implemented checkboxes, but I can't verify whether this will return a collection since my previous problem is halting further progress at the moment.
For reference, here are the models being used.
class Order < ActiveRecord::Base
belongs_to :user
has_many :pizza_orders
accepts_nested_attributes_for :pizza_orders
end
class PizzaOrder < ActiveRecord::Base
belongs_to :pizza, polymorphic: true
belongs_to :order
accepts_nested_attributes_for :pizza, allow_destroy: true
end
class Special < ActiveRecord::Base
belongs_to :pizza
validates :pizza, :presence => true
validates :cost, :presence => true
def get_name_and_cost
"#{pizza.name}: $#{cost}"
end
end
class Pizza < ActiveRecord::Base
has_and_belongs_to_many :toppings
has_many :pizza_orders, as: :pizza
belongs_to :crust
validates :crust, presence: true
end
class Topping < ActiveRecord::Base
has_and_belongs_to_many :pizzas
def get_name_and_cost
"#{self.name}: $#{self.cost}"
end
end
class Crust < ActiveRecord::Base
has_many :pizzas
end
One last thing. This is how I plan on handling strong-typed parameters for the order, but I'm not too sure if it is accurate
def order_params
params.require(:order).permit(:cost, pizza_orders_attributes: [:quantity, pizza_attributes: [:crust, :toppings]])
end

Rails: Multi-model form won't write data to models

Ok this is driving me round the bend. I have three models [which are relevant to this quesiton]: Outfit, Outfit_relationship and Answer. Outfit is the parent model and the others are the childs. The Outfit model looks like this:
class Outfit < ActiveRecord::Base
attr_accessible :user_id, :outfit_origin_id, :outfit_parent_id, :outfitrelationship_id #review before going live
attr_accessible :item_id, :image_size_height, :image_size_width, :image_x_coord, :image_y_coord, :zindex, :outfit_id
attr_accessible :description, :question_id, :user_id, :outfit_id
has_many :answers
has_many :outfit_relationships
accepts_nested_attributes_for :outfit_relationships, :allow_destroy => :true
accepts_nested_attributes_for :answers
Note that the 2nd and 3rd attr_accessible are to access the attributes from the other models. I'm not sure this is absolutely necessary, some articles say it is, some say it isn't, so I put it in.
I've created a multi-model form for this data which I want to publish with one button. Here is the code:
<%= form_for(#outfit) do |post_outfit| %>
<%= post_outfit.fields_for #outfit.outfit_relationships do |build| %>
<table>
<tr>
<td>X Coord <%= build.text_area :image_x_coord, :size => '1x1' %></td>
<td>Y Coord <%= build.text_area :image_y_coord, :size => '1x1' %></td>
<td>Z Index <%= build.text_area :zindex, :size => '1x1' %></td>
<td>Height <%= build.text_area :image_size_height, :size => '1x1' %></td>
<td>Weight <%= build.text_area :image_size_width, :size => '1x1' %></td>
</tr>
</table>
<% end %>
<%= post_outfit.fields_for #outfit.answers do |build| %></br></br>
<%= image_tag current_user.fbprofileimage, :size => "40x40" %></br>
<%= current_user.name %></br>
Comment: <%= build.text_area :description, :size => '10x10' %>
<% end %>
<%= post_outfit.fields_for #outfit do |build| %> </br>
origin id: <%= build.text_area :outfit_origin_id, :size => '1x1' %></br>
parent id: <%= build.text_area :outfit_parent_id, :size => '1x1' %></br>
<% end %>
<div id="ss_QID_actions_container">
<%= post_outfit.submit "Submit checked", :class => "btn btn-small btn-primary" %>
</div>
<% end %>
And here are the relevant buts of the outfit controller:
def new
#outfit = Outfit.new
#outfit.save
#outfit.answers.build
#outfit.outfit_relationships.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: #outfit }
end
end
def create
#outfit = Outfit.new(params[:id])
#comment = #outfit.answers.create(params[:answer])
#outfitrelationship = #outfit.outfit_relationships.create(params[:outfit_relationship])
redirect_to outfit_path(#outfit)
So the problem is nothing gets written into my database apart from the IDs. I'm sure I'm dong something stupid here, but can't figure out why.

Active Admin: Form with datepicker on custom page

Alright I made a custom page in Active Admin called "Newest Rooms" and it shows a table with the Hotel Rooms of the current date.
Now I want to add a form the this custom page where I can pick the Date. I've managed to make the form appear with the Datepicker through:
<%= semantic_form_for :newest_rooms, :builder => ActiveAdmin::FormBuilder do |f|
f.inputs do
f.input :Datum, :as => :datepicker
end
f.buttons
end %>
But no idea how to send this to the right controller and to the method HotelRoom.newest_rooms
I hope someone can explain to me how to do this. I've added the code below:
newest_room.rb
ActiveAdmin.register_page "Newest Rooms" do
menu :label => "Newest Rooms"
content do
render "newest_rooms"
end
end
_newest_room.html.erb
<% #cities = Hotel.cities %>
<%= semantic_form_for :newest_rooms, :builder => ActiveAdmin::FormBuilder do |f|
f.inputs do
f.input :Datum, :as => :datepicker
end
f.buttons
end %>
<ul class="room_list">
<% #cities.each do |c| %>
<li>
<table>
<tr>
<td>
<h2><%= c.City %></h2>
</td>
</tr>
<tr class="room_column">
<td>Hotel</td>
<td>Free Rooms</td>
<td>BN-Price</td>
<td>Old Price</td>
</tr>
<% #rooms = HotelRoom.newest_rooms(c.City) %>
<% #rooms.each do |r| %>
<tr>
<td><%= r.hotel.Hotelname %></td>
<td><%= r.FreeRooms %></td>
<td><b><%= r.Price %>€</b></td>
<td><%= r.OldPrice %>€</td>
</tr>
<%end%>
</table>
</li>
<% end %>
</ul>
hotel_room.rb
class HotelRoom < ActiveRecord::Base
validates :title, :presence => true
self.table_name = "hotel_room"
belongs_to :hotel, :foreign_key => 'H_ID'
accepts_nested_attributes_for :hotel
def to_key
[self.ID]
end
def self.newest_rooms(city)
HotelRoom.find(:all, :joins => :hotel, :conditions => ["hotel.City = ? and hotel_room.Date = ?", city, Date.today])
end
end
add an url to your semantic form, like...
<%= semantic_form_for :newest_rooms, :url => hotel_newest_room_path, :builder => ActiveAdmin::FormBuilder do |f| %>

Rails: Access params of a form with a nested model

I have the following models
class GymUser < ActiveRecord::Base
belongs_to :user
belongs_to :gym
end
class User < ActiveRecord::Base
has_many :gym_users
has_one :gym
attr_accessible :gym_users_attributes, :gym_users
accepts_nested_attributes_for :gym_users
end
I have a form for a new user, with a nested model gym_user. I want to make sure the user doesn't exist already. This is what I'm trying:
def create_member
#user = User.new(params[:user])
#user.generate_password
#dupe = User.find_all_by_email(#user.email)
if(#dupe)
#gym_user = GymUser.new(params[:user][:gym_users_attributes])
#gym_user.user_id = #dupe.id
elsif #user.save
#gym_user = #user.gym_users.order('created_at DESC').first
#gym = Gym.find(#gym_user.gym_id)
end
end
I know there's only one nested model here, but I can't figure out how to access those nested parameters.
Here's the form itself
<%= form_for #user, :as => :user, :remote => true, :url => { :controller => 'users', :action => 'create_member'} do |f| %>
<table border="0" cellpadding="10" cellspacing="0">
<tr>
<td colspan="2">
<%= f.label :name %><br />
<%= f.text_field :name %>
</td>
<td colspan="2">
<%= f.label :email %><br />
<%= f.text_field :email %>
</td>
</tr>
<% f.fields_for :gym_users do |builder| %>
<tr>
<td>
<%= builder.label :role_id, "Role" %><br />
<%= builder.collection_select(:role_id, #roles, :id, :name, {:include_blank => true}, {:onchange => "new_member_role_changed()"}) %>
<%= builder.hidden_field :gym_id, :value => #gym.id %>
</td>
<td>
<%= builder.label :item_id, "Membership Level" %><br />
<%= builder.collection_select(:item_id, #gym.membership_items, :id, :name, {:include_blank => true}) %>
</td>
<td>
<%= builder.label :has_monthly_billing, "Recurring Billing?" %><br />
<%= builder.radio_button :has_monthly_billing, "1" %>Yes
<%= builder.radio_button :has_monthly_billing, "0" %>No
</td>
<td>
<%= builder.label :billing_date %><br />
<%= builder.collection_select(:billing_date, (1..31).to_a, :to_s, :to_s, {:include_blank => true}) %>
</td>
</tr>
<tr>
<td colspan="4">
<%= f.submit %>
Cancel
</td>
</tr>
<% end %>
</table>
<% end %>
I found the answer. I'm not sure if this is the best way but it works
params[:user][:gym_users_attributes].values.first
Your association should be
has_one :gym, :through => gym_users
Also, can you post your form paramaters?
Your focus is on not allowing creation of duplicate users, and you are using email to verify this. You should rather use the helper
validates_uniqueness_of :email
in your User model. As you have a nested attribute, your object will be created only after Rails validates that a user with same email doesn't exist already.
I hope I understood your problem right.

formtastic - subset of values in accepts_nested_attributes_for

I have a model:
class Contact < ActiveRecord::Base
has_many :phones
accepts_nested_attributes_for :phones
end
I want to build 50 phone #s that users can add (there may already be phones 1 or 5, but I always want 50 available)
In my controller:
while contact.phones.length < 50
contact.phones.build({:phone_type_id => PhoneType['a_cool_type'].id})
end
In my view, I want to have 2 columns of phone #s 25 rows each
<%= semantic_form_for contact do |form| %>
<table width=50%>
<%= form.inputs :for => :phones[0..25] do |phone_form| %>
<td align="center"><%= phone_form.input :number, :label => false %></td>
....
<% end %>
</table>
<table width=50%>
<%= form.inputs :for => :phones[25..49] do |phone_form| %>
<td align="center"><%= phone_form.input :number, :label => false %></td>
....
<% end %>
</table>
<%end %>
Obviously the line:
<%= form.inputs :for => :phones[25..49] do |phone_form| %>
doesn't work, but it conveys my intention ( I hope). I want to have more control over how formtastic grabs the underlying object association.
The following works, but I can't do two columns easily without fancy css.
<%= form.inputs :for => :phones do |phone_form| %>
Any suggestions?
---------- Update ----
I was able to get around this in a roundabout way:
I built up a separate list of phone #s not as contact.phones.build, but Phone.new(:contact_id => contact.id) and store those in a list called #new_phones
Then my form looks like this:
<%= semantic_form_for #contact, :url => ..., do |f| %>
<% #new_phones[0...25].each_with_index do |phone, i| %>
<%= f.fields_for :phones, phone, :child_index => i do |phone_form| %>
<%= render "phone_fields", {:phone_form => phone_form, :phone => phone} %>
<%end%>
<% end %>
....
<% #new_phones[25...50].each_with_index do |phone, i| %>
<%= f.fields_for :phones, phone, :child_index => i+25 do |phone_form| %>
<%= render "phone_fields", {:phone_form => phone_form, :phone => phone} %>
<%end%>
<% end %>
<%end%>
This allowed me to display 25 phones on one part of the page, and 25 on another, with nested_attributes_for :phones working as expected on form submit.
I've always had problems with getting nested attributes working as I want but this may help resolve your issue.
Model:
class Contact < ActiveRecord::Base
has_many :phones
accepts_nested_attributes_for :phones
end
Controller:
See we're looping #contract.phones.build 50 times, this creates 50 new instances.
class Contact < ApplicationController
def new
#contact = Contact.new
25.times do
#contact.phones.build
end
end
end
View new.html.erb :
...
<%= p.semantic_fields_for :phones do |ec| %>
<%= ec.input :number %>
<% end %>
...
I did try a few attempts to intercept the loop, sadly with no definite clean avail.

Resources