Im making an application where an user can book a hour of training. I want to give the app the restriction of when an user has already booked one hour of training, it cant book more trainings, at least he deletes it or the book expires.
My code is:
Bookings controller:
Class BookingsController < ApplicationController
before_action :load_training, only: [:create]
def new
@booking = Booking.new
@training = Training.find(params[:training_id])
@booking.training_id
end
def create
@booking = @training.bookings.build(booking_params)
@booking.user = current_user
if @booking.save
flash[:success] = "Book done"
redirect_to trainings_path
else
render 'new'
end
end
def index
@bookings = Booking.where(training_id: params[:training_id])
end
def destroy
@booking = Booking.find(params[:id])
@booking.destroy
flash[:success] = "Book deleted"
redirect_to trainings_path
end
private
def booking_params
params.require(:booking).permit(:user_id, :training_id)
end
def load_training
@training = Training.find(params[:training_id])
end
end
Booking model:
class Booking < ApplicationRecord
belongs_to :user
belongs_to :training
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
validates :training_id, presence: true
end
My routes.rb:
Rails.application.routes.draw do
root 'static_pages#home'
get '/signup', to: 'users#new'
get '/contact', to: 'static_pages#contact'
get '/about', to: 'static_pages#about'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :trainings do
resources :bookings
end
resources :users
end
Index of training view:
<h1>Hours</h1>
<ul class="trainings">
<% @trainings.each do |training| %>
<li>
<%= link_to training.hour, training_path(training) %>
</li>
<% end %>
</ul>
Show of training view:
<div class="row">
<section>
<h1>
HOUR: <%= @training.hour %>
</h1>
</section>
<section>
<h1>
SLOTS: <%= @training.slots %>
</h1>
</section>
<center>
<%= render 'bookings/booking_form' if logged_in? %>
<%= render 'bookings/index_bookings' if logged_in? %>
</center>
Booking_form.html.erb view:
<% unless current_user?(@user) %>
<% if current_user.is_booked(@training) %>
<%= link_to "Delete book", training_booking_path(@training), method: "delete", data: { confirm: 'Are you certain you want to delete this?' }, class: "btn btn-primary" %>
<% else %>
<%= link_to "Book", new_training_booking_path(@training), class: "btn btn-primary" %>
<% end %>
<% end %>
Im recieving the following error:
ActiveRecord::RecordNotFound in BookingsController#destroy
Couldn't find Booking with 'id'=1
Parameters:
{"_method"=>"delete", "authenticity_token"=>"0uUXRwZdbhaKl16QxDi1HCM4H8IwEvGuoFOoxmkHhowoAUgZnlWPybck9DEbCKHh42SqXs3vtc01IRTqbx05wA==", "training_id"=>"1", "id"=>"1"}
I would like to know why the method does not get the booking_id
When i try to see a training hour:
Started GET "/trainings/1" for 127.0.0.1 at 2017-03-11 01:03:23 -0400
Processing by TrainingsController#show as HTML
Parameters: {"id"=>"1"}
Training Load (0.1ms) SELECT "trainings".* FROM "trainings" WHERE "trainings"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendering trainings/show.html.erb within layouts/application
User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Rendered bookings/_booking_form.html.erb (2.3ms)
Rendered trainings/show.html.erb within layouts/application (4.0ms)
Completed 500 Internal Server Error in 6ms (ActiveRecord: 0.2ms)
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"bookings", :id=>nil, :training_id=>"1"} missing required keys: [:id]):
2: <% if current_user.not_booked(@training) %>
3: <%= link_to "Reservar", new_training_booking_path(@training), class: "btn btn-primary" %>
4: <% else %>
5: <%= link_to "Eliminar reserva", training_booking_path(@training, @booking), method: :delete,
6: data: { confirm: 'Are you certain you want to delete this?' }, class: "btn btn-primary" %>
7: <% end %>
8: <% end %>
Training model:
class Training < ApplicationRecord
has_many :users, through: :bookings
has_many :bookings
def can_book?
bookings.count < cantidad
end
end
Training controller:
class TrainingsController < ApplicationController
def show
@training = Training.find(params[:id])
end
def index
@trainings = Training.all
end
end
Thanks
In this line:
<%= link_to "Delete book", training_booking_path(@training), method: "delete", data: { confirm: 'Are you certain you want to delete this?' }, class: "btn btn-primary" %>
I think the path training_booking_path(@training)
should also contain the @booking
instance variable because of the nested routes.
So it should be training_booking_path(@training, @booking), method: :delete
, etc.
You'd have to have @booking
available in your view where the form shows up
I would use rake routes
in your console to confirm the correct path and which resource ids need to be passed in
EDIT:
your trainings controller show action needs to have bookings available as an instance variable:
def show
@training = Training.find(params[:id])
@bookings = @training.bookings
end
Then in your training show view where the form resides, you need to loop over the @bookings and include an individual delete link for each:
<% @bookings.each do |booking| %>
<%= link_to "Delete book", training_booking_path(booking.training, booking), method: :delete, data: { confirm: 'Are you certain you want to delete this?' }, class: "btn btn-primary" %>
<% end %>