The destroy action

這節要完成「delete」的連結和 destroy action 的設定。

首先要為 index 頁面上的每個使用者加上「delete」連結,並限制只有管理員才會看到:

app/views/users/_user.html.erb

<li>
  <%= gravatar_for user, size: 50 %>
  <%= link_to user.name, user %>
  <% if current_user.admin? && !current_user?(user) %>
    | <%= link_to "delete", user, method: :delete,
                                  data: { confirm: "You sure?" } %>
  <% end %>
</li>

注意 method: :delete 參數,它是用來處理 DELETE 請求。

由於瀏覽器無法傳送 DELETE 請求,所以 Rails 會使用 JavaScript 來模擬請求,也就是說如果使用者停止使用 JavaScript,「delete」連結將失去作用。

如果一定要支援沒有啟用 JavaScript 的瀏覽器,可以使用一個發送 POST 請求的表單來模擬 DELETE 請求,詳情參考:Destroy Without JavaScript

加完「delete」連結的畫面如下:

接著設定 destroy action,我們要找到相對應的使用者,刪除使用者,然後導向 index 頁面,因為必須要登入才執行刪除的動作,所以也要把 destroy action 加進 before filter 裡面:

app/controllers/users_controller.rb

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
  before_action :correct_user,   only: [:edit, :update]
  .
  .
  .
  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted"
    redirect_to users_url
  end

  private
  .
  .
  .
end

根據我們之的設定,只有管理員才能刪除使用者,因為只有管理員才看得到「delete」連結,但還是有一個安全的漏洞:只要駭客有足夠經驗,可以透過指令發送 DELETE 請求刪除使用者。因此,我們需要限制對 destroy action 的訪問,只有擁有管理員(admins)身份的使用者才能刪除。

我們要透過 before filter 來限制身份:

app/controllers/users_controller.rb

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
  before_action :correct_user,   only: [:edit, :update]
  before_action :admin_user,     only: :destroy
  .
  .
  .
  private
    .
    .
    .
    # Confirms an admin user.
    def admin_user
      redirect_to(root_url) unless current_user.admin?
    end
end