自定义Controller路由更新active字段为false的实现问题
Hey there! Let's break down how to get this soft-delete (and admin hard-delete) workflow working smoothly for your Document model—this audit-friendly setup makes total sense, so let's fix that routing/action issue you're hitting.
First, we need to add routes for your non-standard delete actions, since the default destroy action is meant for permanent deletion. Open your config/routes.rb and update your documents resources:
resources :documents do member do patch 'soft_delete' # Use PATCH for updating the document's active status delete 'hard_delete' # Use DELETE for permanent removal (admin-only) end end
You can verify these routes exist by running rails routes in your terminal—look for paths like /documents/:id/soft_delete and /documents/:id/hard_delete.
Next, head to your DocumentsController and add the two new actions, along with permission checks to keep things secure.
Soft Delete Action (For Regular Users)
This action will set the active column to false instead of deleting the record:
def soft_delete @document = Document.find(params[:id]) # Optional: Add logic to verify the current user owns this document # unless @document.user == current_user # redirect_to documents_path, alert: "You can't modify this document." # return # end if @document.update(active: false) redirect_to documents_path, notice: 'Document was successfully marked as inactive.' else redirect_to documents_path, alert: 'Failed to mark document as inactive.' end end
Hard Delete Action (Admin-Only)
This action will permanently delete the record, but only for authorized admins:
def hard_delete # First, block non-admin users unless current_user&.admin? redirect_to documents_path, alert: 'You are not authorized to permanently delete documents.' return end @document = Document.find(params[:id]) # Optional: If you're using Active Storage/CarrierWave, purge the attached file first # @document.uploaded_file.purge # Adjust based on your attachment column name if @document.destroy redirect_to documents_path, notice: 'Document was permanently deleted.' else redirect_to documents_path, alert: 'Failed to permanently delete the document.' end end
To keep permission logic clean, you can also extract the admin check into a private method and use a before_action:
before_action :authorize_admin!, only: [:hard_delete] private def authorize_admin! unless current_user&.admin? redirect_to root_path, alert: 'Access denied.' end end
Now, add the appropriate buttons to your views so users can trigger these actions.
Regular User View (Soft Delete Button)
Show this button only for active documents:
<% if @document.active %> <%= button_to 'Mark as Inactive', soft_delete_document_path(@document), method: :patch, class: 'btn btn-warning' %> <% else %> <span class="text-muted">Document is inactive</span> <% end %>
Admin View (Hard Delete Button)
Add this button only for admins (you might want to show it only for inactive documents too, depending on your workflow):
<% if current_user.admin? %> <%= button_to 'Permanently Delete', hard_delete_document_path(@document), method: :delete, class: 'btn btn-danger', data: { confirm: 'Are you sure? This action cannot be undone!' } %> <% end %>
To make sure regular users only see active documents by default, add a scope to your Document model:
class Document < ApplicationRecord scope :active, -> { where(active: true) } end
Then update your index action in the controller:
def index @documents = current_user.admin? ? Document.all : Document.active.all end
- Missing
activecolumn? Run a migration to add it:
Then open the migration file and set a default value:rails generate migration AddActiveToDocuments active:boolean
Rundef change add_column :documents, :active, :boolean, default: true endrails db:migrateto apply it. - Routing errors? Double-check that you're using the correct path helper (e.g.,
soft_delete_document_path(@document)instead ofdocument_soft_delete_path). Runrails routesto confirm. - Permission issues? Test with both regular and admin users to ensure actions are restricted correctly.
内容的提问来源于stack exchange,提问作者Ben Pohl

