Reputation: 1047
I am learning Rails by writing a simple restaurant app. I have a restaurant model, meal model and an order model. I want to be able to send order to the restaurant by clicking buy button next to a certain meal. I am able to create an order and send it to the restaurant but I do not know how to link that order to the meal.
These are the models and the routes:
class Order < ActiveRecord::Base
belongs_to :restaurant
end
class Restaurant < ActiveRecord::Base
has_many :meals
has_many :orders
end
class Meal < ActiveRecord::Base
belongs_to :restaurant
end
resources :restaurants do
resources :staff_members
resources :meals
resources :orders
end
Meals are listed and below each meal, I render a form for creating an order. This is wrong for sure but I cannot find how to do that properly.. I would be so thankful to anybody who could help with this!
Upvotes: 0
Views: 82
Reputation: 394
Try has_many :through association like this.
class Meal < ActiveRecord::Base
has_many :orders
belongs_to :restaurant
end
class Order < ActiveRecord::Base
belongs_to :meal
has_one :restaurant, through: :meal
end
class Restaurant < ActiveRecord::Base
has_many :meals
has_many :orders, through: :meals
end
Basically, you'll have to create meal that belongs_to a restaurant. Then for each of the meals in the list of meals for a restaurant, you'll have a form with a button to order. That form is to create an order that belongs_to the corresponding meal. In turn, the meal will automatically belong to the restaurant through the associations mentioned above because the order belongs to the meal and the meal belongs to the restaurant.
Edit:
(Assuming that you have a username field in the Order model as an example; and your route is set as get '/restaurants/:restaurant_id/meals/:meal_id/orders/new' => 'orders#new'
)
Orders Controller
def new
@meal = Meal.find(params[:meal_id])
end
def create
@meal = Meal.find(params[:meal_id])
@order = @meal.orders.build(order_params)
if @order.save
flash[:success] = "Successfully created the order..."
redirect_to root_url
else
flash[:danger] = "Failed to create the order..."
redirect_to request.referrer # Redirects back to the last url
end
end
private
def order_params
params.require(:order).permite(:username, :more_order_fields) # Add other fields for order here
end
Form for new order
<%= form_for(@meal.orders.build) do |order_form| %>
<%= hidden_field_tag :meal_id, params[:meal_id] %>
<%= order_form.label :username %>
<%= order_form.text_field :username %>
<%= order_form.submit "Create Order" %>
<% end %>
I haven't tested the code yet. But hope it gives you a good idea of the procedure at least.
Upvotes: 1
Reputation: 6692
My idea is:
meal
belongs to a restaurant
and has available_amount
order
is created, it has many meals but these meals are not meal
actually, it is only 1 of available_amount
meals.So I suggest adding a new model called OrderedMeal
, the new schema will be like:
class Order < ActiveRecord::Base
belongs_to :restaurant
has_many :ordered_meals # Change here
end
class Restaurant < ActiveRecord::Base
has_many :meals
has_many :orders
end
class Meal < ActiveRecord::Base
belongs_to :restaurant
end
class OrderedMeal < ActiveRecord::Base
belongs_to :meal
belongs_to :order
end
ordered_meals
, then decrease the value of available_amount
for each meal, I just suggest having available_amount
if it is actually needed!Order
belongs to Restaurant
may be redundant since you can get the restaurant
info from ordered_meals
----> meal
----> restaurant
, you can consider to remove it.Upvotes: 1
Reputation: 6418
I will do it like this:
In routes:
resources :meals do
member do
post :new_order
end
end
Now this will create a new member route. Now I will submit the form to this action and in the meals_controller
I will write:
def new_order
@meal = Meal.find(params[:id]) # Skip if already present in a before_action
if @meal.create_order(current_user)
# success response
else
# error message
end
end
In the Meal
model create an instance method:
def create_order(user)
# user because obviously order will belong to some user
restaurant.orders.create(meal: self, user: user, other attributes)
end
There can be more better ways but mine would be this. And this code is not tested may have errors but will give you an idea.
Hope this helps.
Upvotes: 1