ActionController::ParameterMissing 使用自定义路线
ActionController::ParameterMissing with custom route
我正在构建一个数字图书馆,目前我正在尝试将 soft_delete 添加到应用程序,但我遇到了显示
错误的问题
ActionController::ParameterMissing in BooksController#update
param is missing or the value is empty: book
soft_delete 方法的作用是将其在数据库中的 table 从默认的 false 值更新为 true。我检查了我的代码,但找不到问题出在哪里。
图书模型
class Book < ApplicationRecord
#add a model scope to fetch only non-deleted records
scope :not_deleted, -> { where(soft_deleted: false) }
scope :deleted, -> { where(soft_deleted: true) }
#create the soft delete method
def soft_delete
update(soft_deleted: true)
soft_deleted
end
# make an undelete method
def undelete
update(soft_deleted: false)
end
end
书籍控制器(截断)
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :soft_delete, :destroy]
def index
@books = Book.not_deleted
end
...
def destroy
@book.destroy
respond_to do |format|
format.html { redirect_to books_url, notice: 'Book was successfully destroyed.' }
format.json { head :no_content }
end
end
def soft_delete
respond_to do |format|
@book.soft_delete(book_params)
format.html { redirect_to books_url, notice: 'Book was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
@book = Book.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:name, :author, :description, :soft_deleted)
end
end
路线
Rails.application.routes.draw do
resources :books
put '/books/:id' => 'books#soft_delete'
end
图书索引视图
<h1>Books</h1>
<tbody>
<% @books.each do |book| %>
<tr>
<td><%= book.name %></td>
<td><%= book.author %></td>
<td><%= book.description %></td>
<td><%= link_to 'Show', book %></td>
<td><%= link_to 'Edit', edit_book_path(book) %></td>
<td><%= link_to 'Destroy', book, method: :delete, data: { confirm: 'Are you sure?' } %></td>
<td><%= link_to 'Soft Delete', book, method: :put, data: { confirm: 'Are you sure?' } %></td>
soft_delete
</tr>
<% end %>
</tbody>
Rails 将 <%= link_to 'Soft Delete', book, method: :put...%>
路由到 update
操作,因为 resource :books
是在您的自定义路由之前定义的,并且 Rails 使用与请求。
运行 rails routes -g books
在终端中,你会看到如下内容:
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
PUT /books/:id(.:format) books#soft_delete
如您所见,books#update
和 books#soft_delete
的路由相同。
您可以通过创建命名路由来修复它:put '/books/:id' => 'books#soft_delete', as: 'soft_delete'
:
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
soft_delete PUT /books/:id(.:format) books#soft_delete
然后,修改您的模板以使用新的助手:<%= link_to 'Soft Delete', soft_delete_path(book), method: :put...%>
我建议你不要使用像
put '/books/:id' => 'books#soft_delete'
Rails 有 'member routes',所以你可以这样重写你的路线:
resources :books, only: %i[index destroy] do
member { put :soft_delete }
end
我在这里使用了选项 'only',它允许您只为您定义必要的路线(不是全部 7 条,而是 2 条 - 索引和销毁)
首先:您已经定义了 resources :books
。此定义为您创建了 7 条路线:
books GET /books(.:format) -> books#index
POST /books(.:format) -> books#create
new_book GET /books/new(.:format) -> books#new
edit_book GET /books/:id/edit(.:format) -> books#edit
book GET /books/:id(.:format) -> books#show
PATCH /books/:id(.:format) -> books#update (this and next route are the same, and considering as 1, so we have 7 routes, not 8)
PUT /books/:id(.:format) -> books#update
DELETE /books/:id(.:format) -> books#destroy
因此使用方法 PUT 和路径 '/books/:id' 的路径已经存在,你的 put '/books/:id' => 'books#soft_delete'
将永远不会被使用。这就是触发错误的原因:'ActionController::ParameterMissing in BooksController#update ' - 您的 link 点击触发了 BooksController#update 操作调用,这需要参数中的书键。
其次:
我建议您从模型中删除方法 :soft_delete 和 :undelete。 Rails 提供方法 :toggle!用于即时写入数据库和 :toggle 用于更改值而不立即保存更改。所以你可以直接在控制器中写这样的代码:
book = Book.find_by(id: params[:id])
book.toggle!(:soft_deleted)
请注意,第 soft_deleted 列应该是布尔值才能使其生效。
你的link应该是这样的:
link_to 'Soft Delete', soft_delete_book_path(book), data: { method: :put }
我正在构建一个数字图书馆,目前我正在尝试将 soft_delete 添加到应用程序,但我遇到了显示
错误的问题ActionController::ParameterMissing in BooksController#update
param is missing or the value is empty: book
soft_delete 方法的作用是将其在数据库中的 table 从默认的 false 值更新为 true。我检查了我的代码,但找不到问题出在哪里。
图书模型
class Book < ApplicationRecord
#add a model scope to fetch only non-deleted records
scope :not_deleted, -> { where(soft_deleted: false) }
scope :deleted, -> { where(soft_deleted: true) }
#create the soft delete method
def soft_delete
update(soft_deleted: true)
soft_deleted
end
# make an undelete method
def undelete
update(soft_deleted: false)
end
end
书籍控制器(截断)
class BooksController < ApplicationController
before_action :set_book, only: [:show, :edit, :update, :soft_delete, :destroy]
def index
@books = Book.not_deleted
end
...
def destroy
@book.destroy
respond_to do |format|
format.html { redirect_to books_url, notice: 'Book was successfully destroyed.' }
format.json { head :no_content }
end
end
def soft_delete
respond_to do |format|
@book.soft_delete(book_params)
format.html { redirect_to books_url, notice: 'Book was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_book
@book = Book.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def book_params
params.require(:book).permit(:name, :author, :description, :soft_deleted)
end
end
路线
Rails.application.routes.draw do
resources :books
put '/books/:id' => 'books#soft_delete'
end
图书索引视图
<h1>Books</h1>
<tbody>
<% @books.each do |book| %>
<tr>
<td><%= book.name %></td>
<td><%= book.author %></td>
<td><%= book.description %></td>
<td><%= link_to 'Show', book %></td>
<td><%= link_to 'Edit', edit_book_path(book) %></td>
<td><%= link_to 'Destroy', book, method: :delete, data: { confirm: 'Are you sure?' } %></td>
<td><%= link_to 'Soft Delete', book, method: :put, data: { confirm: 'Are you sure?' } %></td>
soft_delete
</tr>
<% end %>
</tbody>
Rails 将 <%= link_to 'Soft Delete', book, method: :put...%>
路由到 update
操作,因为 resource :books
是在您的自定义路由之前定义的,并且 Rails 使用与请求。
运行 rails routes -g books
在终端中,你会看到如下内容:
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
PUT /books/:id(.:format) books#soft_delete
如您所见,books#update
和 books#soft_delete
的路由相同。
您可以通过创建命名路由来修复它:put '/books/:id' => 'books#soft_delete', as: 'soft_delete'
:
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
soft_delete PUT /books/:id(.:format) books#soft_delete
然后,修改您的模板以使用新的助手:<%= link_to 'Soft Delete', soft_delete_path(book), method: :put...%>
我建议你不要使用像
put '/books/:id' => 'books#soft_delete'
Rails 有 'member routes',所以你可以这样重写你的路线:
resources :books, only: %i[index destroy] do
member { put :soft_delete }
end
我在这里使用了选项 'only',它允许您只为您定义必要的路线(不是全部 7 条,而是 2 条 - 索引和销毁)
首先:您已经定义了 resources :books
。此定义为您创建了 7 条路线:
books GET /books(.:format) -> books#index
POST /books(.:format) -> books#create
new_book GET /books/new(.:format) -> books#new
edit_book GET /books/:id/edit(.:format) -> books#edit
book GET /books/:id(.:format) -> books#show
PATCH /books/:id(.:format) -> books#update (this and next route are the same, and considering as 1, so we have 7 routes, not 8)
PUT /books/:id(.:format) -> books#update
DELETE /books/:id(.:format) -> books#destroy
因此使用方法 PUT 和路径 '/books/:id' 的路径已经存在,你的 put '/books/:id' => 'books#soft_delete'
将永远不会被使用。这就是触发错误的原因:'ActionController::ParameterMissing in BooksController#update ' - 您的 link 点击触发了 BooksController#update 操作调用,这需要参数中的书键。
其次: 我建议您从模型中删除方法 :soft_delete 和 :undelete。 Rails 提供方法 :toggle!用于即时写入数据库和 :toggle 用于更改值而不立即保存更改。所以你可以直接在控制器中写这样的代码:
book = Book.find_by(id: params[:id])
book.toggle!(:soft_deleted)
请注意,第 soft_deleted 列应该是布尔值才能使其生效。
你的link应该是这样的:
link_to 'Soft Delete', soft_delete_book_path(book), data: { method: :put }