Reputation: 1047
I am writing an app which has a Restaurant, Menu, Category, and Meal models. How to implement these without nesting more than 2 levels deep?
class Restaurant < ActiveRecord::Base
has_many :menus
has_many :categories, through: :menus
has_many :meals, through: :categories
end
class Menu < ActiveRecord::Base
has_many :categories
has_many :meals, through: :categories
end
class Category < ActiveRecord::Base
has_many :meals
end
class Meal < ActiveRecord::Base
belongs_to :category
end
What I am asking for is how to write the routes. Without nesting the links would look like:
restaurants GET /restaurants(.:format) restaurants#index
....
menus GET /menus(.:format) menus#index
....
categories GET /categories(.:format) categories#index
....
How am I then going to reach restaurants/1/menus/2/categories/3/meals/2 for example?
Upvotes: 1
Views: 143
Reputation: 8668
The standard way is to not use nested routes to access items.
With the normal routes
Rails.application.routes.draw do
resources :restaurants
resources :menus
resources :meals
resources :categories
end
you get all the routes you need:
Prefix Verb URI Pattern Controller#Action
menus GET /menus(.:format) menus#index
POST /menus(.:format) menus#create
new_menu GET /menus/new(.:format) menus#new
edit_menu GET /menus/:id/edit(.:format) menus#edit
menu GET /menus/:id(.:format) menus#show
PATCH /menus/:id(.:format) menus#update
PUT /menus/:id(.:format) menus#update
DELETE /menus/:id(.:format) menus#destroy
restaurants GET /restaurants(.:format) restaurants#index
POST /restaurants(.:format) restaurants#create
new_restaurant GET /restaurants/new(.:format) restaurants#new
edit_restaurant GET /restaurants/:id/edit(.:format) restaurants#edit
restaurant GET /restaurants/:id(.:format) restaurants#show
PATCH /restaurants/:id(.:format) restaurants#update
PUT /restaurants/:id(.:format) restaurants#update
DELETE /restaurants/:id(.:format) restaurants#destroy
meals GET /meals(.:format) meals#index
POST /meals(.:format) meals#create
new_meal GET /meals/new(.:format) meals#new
edit_meal GET /meals/:id/edit(.:format) meals#edit
meal GET /meals/:id(.:format) meals#show
PATCH /meals/:id(.:format) meals#update
PUT /meals/:id(.:format) meals#update
DELETE /meals/:id(.:format) meals#destroy
categories GET /categories(.:format) categories#index
POST /categories(.:format) categories#create
new_category GET /categories/new(.:format) categories#new
edit_category GET /categories/:id/edit(.:format) categories#edit
category GET /categories/:id(.:format) categories#show
PATCH /categories/:id(.:format) categories#update
PUT /categories/:id(.:format) categories#update
DELETE /categories/:id(.:format) categories#destroy
So if you have a @meal of restaurant#1 with id:5 you link to it by
<%= link_to @meal %>
and get the path /meals/5
.
OK, it can be handy to manage meals by restaurant (especially list
and new
).
You can add nested routes just for that:
Rails.application.routes.draw do
resources :restaurants do
resources :menus, only: [:index,:new]
end
resources :menus do
resources :meals, only: [:index,:new]
end
resources :meals
resources :categories
end
and get some new routes:
Prefix Verb URI Pattern Controller#Action
restaurant_menus GET /restaurants/:restaurant_id/menus(.:format) menus#index
new_restaurant_menu GET /restaurants/:restaurant_id/menus/new(.:format) menus#new
restaurant_meals GET /restaurants/:restaurant_id/meals(.:format) meals#index
new_restaurant_meal GET /restaurants/:restaurant_id/meals/new(.:format) meals#new
...
menu_meals GET /menus/:menu_id/meals(.:format) meals#index
new_menu_meal GET /menus/:menu_id/meals/new(.:format) meals#new
Nesting is never deeper than 1.
Now you can link to all meals of one restaurant by
<%= link_to 'All Meals', restaurant_meals(@restaurant) %>
and to all meals of a menu by
<%= link_to 'All Meals', menu_meals(@menu) %>
As you can see, all these link call meal#index, so your controller has to take care of the different lists, i.e.:
class MealsController < ApplicationController
# GET /meals
# GET /restaurants/:restaurant_id/meals
# GET /menus/:menu_id/meals
def index
if params[:restaurant_id].present?
@restaurant = Restaurant.find params[:restaurant_id]
@meals = @restaurant.meals
elsif params[:menu_id].present?
@menu = Menu.find params[:menu_id]
@meals = @menu.meals
else
@meals = Meal.all
end
end
end
Upvotes: 1