I have three models:
class User < ActiveRecord::Base
has_many :administrations
has_many :calendars, through: :administrations
end
class Calendar < ActiveRecord::Base
has_many :administrations
has_many :users, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
And here are my routes:
resources :users do
resources :administrations
resources :calendars
end
———————————
UPDATE:
Here is what I get when I run rake routes
in Terminal:
Prefix Verb URI Pattern Controller#Action
user_administrations GET /users/:user_id/administrations(.:format) administrations#index
POST /users/:user_id/administrations(.:format) administrations#create
new_user_administration GET /users/:user_id/administrations/new(.:format) administrations#new
edit_user_administration GET /users/:user_id/administrations/:id/edit(.:format) administrations#edit
user_administration GET /users/:user_id/administrations/:id(.:format) administrations#show
PATCH /users/:user_id/administrations/:id(.:format) administrations#update
PUT /users/:user_id/administrations/:id(.:format) administrations#update
DELETE /users/:user_id/administrations/:id(.:format) administrations#destroy
user_calendars GET /users/:user_id/calendars(.:format) calendars#index
POST /users/:user_id/calendars(.:format) calendars#create
new_user_calendar GET /users/:user_id/calendars/new(.:format) calendars#new
edit_user_calendar GET /users/:user_id/calendars/:id/edit(.:format) calendars#edit
user_calendar GET /users/:user_id/calendars/:id(.:format) calendars#show
PATCH /users/:user_id/calendars/:id(.:format) calendars#update
PUT /users/:user_id/calendars/:id(.:format) calendars#update
DELETE /users/:user_id/calendars/:id(.:format) calendars#destroy
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
root GET / static_pages#home
———————————
UPDATE 2:
Here is my calendars_controller.rb
file:
class CalendarsController < ApplicationController
before_action :set_calendar, only: [:show, :edit, :update, :destroy]
# GET /calendars
# GET /calendars.json
def index
@calendars = Calendar.all
end
# GET /calendars/1
# GET /calendars/1.json
def show
end
# GET /calendars/new
def new
@user = User.find(params[:user_id])
@calendar = @user.calendars.new
end
# GET /calendars/1/edit
def edit
@user = User.find(params[:user_id])
@calendar = @user.calendar.find(params[:calendar_id])
end
# POST /calendars
# POST /calendars.json
def create
@user = User.find(params[:user_id])
@calendar = @user.calendars.new(calendar_params)
respond_to do |format|
if @calendar.save
format.html { redirect_to user_calendar_path(@user,@calendar), notice: 'Calendar was successfully created.' }
format.json { render :show, status: :created, location: @calendar }
else
format.html { render :new }
format.json { render json: @calendar.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /calendars/1
# PATCH/PUT /calendars/1.json
def update
respond_to do |format|
if @calendar.update(calendar_params)
format.html { redirect_to @calendar, notice: 'Calendar was successfully updated.' }
format.json { render :show, status: :ok, location: @calendar }
else
format.html { render :edit }
format.json { render json: @calendar.errors, status: :unprocessable_entity }
end
end
end
# DELETE /calendars/1
# DELETE /calendars/1.json
def destroy
@calendar.destroy
respond_to do |format|
format.html { redirect_to calendars_url, notice: 'Calendar was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_calendar
@calendar = Calendar.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def calendar_params
params.require(:calendar).permit(:name)
end
end
———————————
http://localhost:3000/users/1/calendars/new
and http://localhost:3000/users/1/calendars/1
work fine.
But, whenever I try to access http://localhost:3000/users/1/calendars
, I get the following error:
ActionController::UrlGenerationError in Calendars#index
Showing /Users/TXC/code/rails/calendy/app/views/calendars/index.html.erb where line #17 raised:
No route matches {:action=>"show", :controller=>"calendars", :id=>nil, :user_id=>nil} missing required keys: [:id, :user_id]
Extracted source (around line #17):
<tr>
<td><%= calendar.name %></td>
<td><%= link_to 'Show', user_calendar_path(@user, @calendar) %></td>
<td><%= link_to 'Edit', edit_user_calendar_path(@user, @calendar) %></td>
<td><%= link_to 'Destroy', calendar, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
In particular, I don't understand the missing required keys: [:id, :user_id]
part, since I have both @user
and @calendar
in my user_calendar_path
.
Obviously, I am missing something, but I cannot figure out what.
Any idea?
The problem here is, you are hitting http://localhost:3000/users/1/calendars
url which maps to your calendars#index
action and the correct path for this is: user_calendars_path
and it needs only one param user_id
as it will take you to the index page for the user and will show all the user calendars from the database.
But, in your index.html.erb
view, you have this:
<td><%= link_to 'Edit', edit_user_calendar_path(@user, @calendar) %></td>
which you can't have because for the index
action in your controller, you did not set the @user
and @calendar
. You can use this in show.html.erb
but not in index.html.erb
. So, that's why you are getting this error.
In short, you can't have this in your index.html.erb
:
<td><%= link_to 'Show', user_calendar_path(@user, @calendar) %></td>
because this is mapped to calendars#show
action and the corresponding view should be show.html.erb
BUT currently you have it inside index.html.erb
!
To answer your last question:
In particular, I don't understand the missing required keys: [:id, :user_id] part, since I have both @user and @calendar in my user_calendar_path.
Yes, you have @user
and @calendar
defined in your controller BUT in the show
method AND user_calendar_path
maps to that calendars#show
method. But hey! you are calling this from the index.html.erb
which corresponds to calendars#index
action. That's what you are missing. Hope it's clear now :-)
Finally, the difference is subtle.
user_calendars_path
is for index
view which shows you all the calendars for a particular user. In this case, you have to have a @user
set in the index
action in your controller.
user_calendar_path
is for show
which will take you to a particular calendar of a particular user. In this case, you have to have @user
and @calendar
set in the show
method of your controller.