Я создаю цифровую библиотеку и прямо сейчас пытаюсь добавить soft_delete в приложение, но у меня возникают проблемы с отображением ошибки
ActionController::ParameterMissing in BooksController#update
param is missing or the value is empty: book
Действие метода soft_delete состоит в том, чтобы обновить свою таблицу в базе данных со значения 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 есть «членские маршруты», поэтому вы можете переписать свои маршруты следующим образом:
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» — ваш щелчок по ссылке вызвал вызов действия BooksController#update, для которого требуется ключ книги в параметрах.
Во-вторых: Я предлагаю вам удалить методы :soft_delete и :undelete из модели. Rails предоставляет методы :toggle! для мгновенной записи в БД и :toggle для изменения значения без немедленного сохранения изменений. Таким образом, вы можете написать прямо в контроллере такой код:
book = Book.find_by(id: params[:id])
book.toggle!(:soft_deleted)
Обратите внимание, что столбец soft_deleted должен быть логическим, чтобы это работало.
ваша ссылка должна быть такой:
link_to 'Soft Delete', soft_delete_book_path(book), data: { method: :put }
Пожалуйста, позвольте мне узнать больше о том, как вы так хорошо изучили рубин? Я хотел бы стать лучшим разработчиком Ruby, пожалуйста.
конечно) Для начала вы можете найти много полезной информации о рельсах здесь Guides.rubyonrails.org. Для изучения рубиновых методов - ruby-doc.org.
Спасибо большое. Пожалуйста, могу ли я связаться с вами любым другим способом или с помощью любой другой платформы, если у меня возникнут проблемы с моим кодом? Ваше решение кажется очень простым и чистым.
Я рад помочь, так что вы можете указать свое имя на facebook
Меня на Facebook зовут Promise Chukwuenyem. Спасибо. fb.com/promisepreston1
Проблема в форме, которую вы используете для отправки. Эта строка
@book.soft_delete(book_params)
в методе обновления означает, что вы используетеbook_params
, который требуетbook
. Параметры должны выглядеть примерно так: `:book => {title: 'title here',....}}
. Если вы посмотрите на отправляемые параметры, в них будет отсутствовать этот внешний объектbook
, охватывающий атрибуты, которые вы отправляете. Можете ли вы опубликовать, как выглядят отправленные параметры?