The problem I am facing with Formtastic
is that I have a Form to create a new Order
. In this form I want to select multiple existing Food
items from a list. These should be added to the new Order I am submitting. At the same time I also want to set attributes in the FoodOrder
join model. This Model has an integer quantity attribute for which i would like to have a field in my form.
What I am basically looking for is a form that lists all Food Items and puts a field for the quantity
on the same line as the Food Item it belongs to.
The Models
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :restaurant
has_many :food_orders
has_many :foods, :through => :food_orders
end
class FoodOrder < ActiveRecord::Base
belongs_to :food
belongs_to :order
end
class Food < ActiveRecord::Base
has_many :food_orders
has_many :orders, :through => :food_orders
belongs_to :category
end
This is one of the versions of the form I have tried so far. But I am just baffled and do not know how to get fields for the FoodOrder Model.
<%= semantic_form_for [@restaurant, @order] do |f| %>
<%= f.inputs do %>
<%= f.input :comment %><br />
<%= f.input :table_id %><br />
<%# <%= f.input :foods, :as => :check_boxes %>
<%= f.inputs :for => :foods do |food| %>
<%= food %>
<%= food.inputs :quantity %>
<% end %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button %>
<% end %>
<% end %>
My models have these attributes
create_table "food_orders", :force => true do |t|
t.integer "quantity", :null => false
t.decimal "price", :null => false
t.integer "food_id", :null => false
t.integer "order_id", :null => false
t.text "comment"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "foods", :force => true do |t|
t.integer "category_id", :null => false
t.string "name", :null => false
t.string "description"
t.string "image"
t.decimal "default_price", :null => false
t.boolean "active", :default => true, :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "orders", :force => true do |t|
t.integer "restaurant_id", :null => false
t.integer "user_id", :null => false
t.integer "table_id", :null => false
t.decimal "total", :null => false
t.datetime "finished_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
Basically what I would end up doing is creating a FoodOrder
object for each Food
then only save the ones that have a value above 0.
You could do that in a reject_if
for the accepts_nested_attributes_for
but that wouldn't deleted the old FoodOrder
s that someone might change from 3 to 0. So instead you will have to override the quantity=
method for FoodOrder
.
I've never used formtastic
before but I'm going to take a guess and say that this should work.
<%= semantic_form_for [@restaurant, @order] do |f| %>
<%= f.inputs do %>
<%= f.input :comment %><br />
<%= f.input :table_id %><br />
<% @foods.each do |food|
<%= f.semantic_fields_for :food_orders,
@order.food_orders.detect_or_build_by_food(food)
do |food_order| %>
<%= food %>
<%= food_order.inputs :quantity %>
<% end %>
<% end %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button %>
<% end %>
<% end %>
order.rb:
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :restaurant
has_many :foods, :through => :food_orders
has_many :food_orders do
def detect_or_build_by_food(food)
record = self.detect{ |food_order| food_order.food_id == food.id }
if record.nil?
record = self.build(:food => food)
end
record
end
end
accepts_nested_attributes_for :food_orders
end
food_order.rb:
class FoodOrder < ActiveRecord::Base
belongs_to :food
belongs_to :order
def quantity=(quantity)
if quantity <= 0
self.destroy
else
self[:quantity] = quantity
end
end
end
I would hope that works but it is untested code, so yeah... Good Luck!