我创建了一个Web应用程序,用户可以在其中预订一小时的培训。我希望这个应用程序让用户删除它,如果它想要的话。当我到达unbook按钮时,它会显示一条错误消息:
BookingsController#destroy中的ActiveRecord :: RecordNotFound
找不到带有' id' = 14
的预订
我想知道为什么会发生这种情况以及如何解决这个问题,以便成功完成预订的删除。
预订管制员:
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] = "Reservacion creada"
redirect_to trainings_path
else
render 'new'
end
end
def index
@bookings = Booking.where(training_id: params[:training_id])
end
def destroy
Booking.find(params[:id]).destroy
flash[:success] = "Reservacion eliminada"
redirect_to trainings_path
end
private
def booking_params
params.require(:booking).permit(:id, :user_id, :training_id)
end
def load_training
@training = Training.find(params[:training_id])
end
end
训练节目:
<div class="row">
<section>
<h1>
HOUR: <%= @training.hour %>
</h1>
</section>
<section>
<h1>
SLOTS: <%= @training.left_slots %>
</h1>
</section>
<center>
<%= render 'bookings/booking_form' if logged_in? %>
<%= render 'bookings/index_bookings' if logged_in? %>
</center>
Booking_form:
<% unless current_user?(@user) %>
<% if current_user.not_booked?(@training) %>
<%= link_to "Book", new_training_booking_path(@training),
class: "btn btn-primary" %>
<% else %>
<%= link_to "Unbook", training_booking_path(@training),
method: :delete, data:{ confirm: 'You sure?' },
class: "btn btn-primary" %>
<% end %>
<% end %>
config.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 :users
resources :trainings do
resources :bookings
end
end
培训模式:
class Training < ApplicationRecord
has_many :users, through: :bookings
has_many :bookings
def can_book?
bookings.count < slots
end
def left_slots
slots - bookings.count
end
end
预订模式:
class Booking < ApplicationRecord
belongs_to :user
belongs_to :training
validates :user_id, presence: true
validates :training_id, presence: true
validate :training_not_full?, on: :create
private
def training_not_full?
errors.add(:base, :full, message: "Full training") unless training.can_book?
end
end
用户模型:
class User < ApplicationRecord
has_many :trainings, through: :bookings
has_many :bookings
def not_booked?(training)
bookings.where(training: training).none?
end
end
由于
答案 0 :(得分:2)
它是一种嵌套路线。您需要指定培训和预订才能删除。而不是......
<%= link_to "Unbook", training_booking_path(@training),
method: :delete, data:{ confirm: 'You sure?' },
class: "btn btn-primary" %>
做...
<%= link_to "Unbook", training_booking_path(@training, @training.bookings.where(user: current_user).first,
method: :delete, data:{ confirm: 'You sure?' },
class: "btn btn-primary" %>
答案 1 :(得分:0)
在您的预订表单中,您只会发送培训的ID,而不是预订。 因此,它试图删除具有训练ID的书。您应该发送培训的ID和预订。
如果你rake routes
,你会有这样的路线:
DELETE /trainings/:training_id/bookings/:id(.:format) bookings#destroy
这需要培训ID和预订ID。
<%= link_to "Unbook", training_booking_path(@training, <the booking object>),
如果培训有多次预订,您必须决定系统如何决定要删除的预订。 @ training.bookings.first,很可能会返回第一个预订。
答案 2 :(得分:0)
由于booking
是嵌套资源(取决于training
),因此您需要将@training
和@booking
的ID传递给网址助手。
<%= link_to "Unbook", training_booking_path(@training), method: :delete %>
在上面的代码段中,网址应为training_booking_path(@training, @booking)
,或者您甚至可以将其简化为
<%= link_to "Unbook", [@training, @booking], method: :delete %>
(为简洁起见,data
和class
选项已被排除。
确保在负责显示链接的视图的控制器操作中定义了@booking
。
Rails会根据DELETE
选项和目标/trainings/#{@training.id}/bookings/#{@booking.id}
method: :delete
发送[@training, @booking]
个请求
您可以通过运行rake routes
找到确切的路径,您应该找到以下条目:
DELETE /trainings/:training_id/bookings/:id bookings#destroy
因此,在destroy
方法中,您可以使用
booking
# in bookings_controller.rb
class BookingsController < ApplicationController
before_action :set_training # you need to find the training before performing any action
# other actions
def destroy
@booking = @training.bookings.find(params[:id])
@booking.destroy
# flash setting & redirect
end
private
def set_training
@training = Training.find(params[:training_id])
end
要了解有关路由嵌套资源的更多信息,请阅读文档here