我必须在 routes.rb 中指定操作吗?

Do I have to specify actions in routes.rb?

当我阅读 Rails 4 in Action 时,我正在尝试实现我自己的应用程序,因此它看起来与书中的不一样。 本书对应的提交是Section 7.2.3: Only admins can create or delete projects

在我的例子中,管理员只能删除项目item对应书中的project)。

我的回购 https://github.com/tenzan/shop and deployed http://ichiba-demo.herokuapp.com/

我要应用的规则是:

  1. 普通用户(您可以使用 staff@example.com/password 登录)可以执行除 destroy 操作之外的所有操作。
  2. 管理员 (admin@example.com/password) 只能 destroy.

意识到我有:

admin/items_controller.rb中:

    class Admin::ItemsController < Admin::ApplicationController

      def destroy
        @item = Item.find(params[:id])
        @item.destroy

        flash[:notice] = 'Item has been deleted.'
        redirect_to items_path
      end

      private

      def item_params
        params.require(:item).permit(:name, :quantity)
      end

    end

controllers/items_controller.rb中:

class ItemsController < ApplicationController
  before_action :set_item, only: [:show, :edit, :update]

  def index
    @items = Item.all
  end

  def new
    @item = Item.new
  end

  def create
    @item = Item.new(item_params)

    if @item.save
      flash[:notice] = 'Item has been created.'
      redirect_to @item
    else
      flash.now[:alert] = 'Item has not been created.'
      render 'new'
    end
  end

  def show
  end

  def edit
  end

  def update

    if @item.update(item_params)
      flash[:notice] = 'Item has been updated.'
      redirect_to @item
    else
      flash.now[:alert] = 'Item has not been updated.'
      render 'edit'
    end
  end

  private

  def set_item
    @item = Item.find(params[:id])
  rescue ActiveRecord::RecordNotFound
    flash[:alert] = 'The item could not be found.'
    redirect_to items_path
  end

  def item_params
    params.require(:item).permit(:name, :quantity)
  end
end

routes.rb中:

Rails.application.routes.draw do
  namespace :admin do
    root 'application#index'

    resources :items, only: :destroy
  end

  devise_for :users
  root 'items#index'

  resources :items, only: [:index, :show, :edit, :update, :new, :create] do
    resources :comments
  end
end

问题:

  1. 我是否必须在 routes.rb 中指定操作,因为我已经指定了谁可以在其相应的控制器中使用哪些操作?当我从 routes.rb...
  2. 中删除它们时,我没有注意到任何变化
  3. 当我在 routes.rbcontrollers/items_controllers.rb 两个地方指定操作时,我是否违反了 DRY 概念?

如果您指出其他地方需要改进以满足最佳实践,我会很高兴。

PS: 主题可能比较模糊,欢迎编辑。

Do I have to specify actions in the routes.rb, as I already have specified who can use what actions in their corresponding controllers?

是的。例如,如果您在 items_controller.rb 控制器中只有一个操作(比如说 show),然后离开

resources :items do # no specified actions
  #...
end

routes.rb 中它会为项目控制器生成所有路由(对于 newcreateeditdestroyupdate ETC)。但是在 routes.rb 中指定操作会将生成的路由限制为仅需要。

Am I violating DRY concept, when I specify actions in 2 places, i.e. in the routes.rb and controllers/items_controllers.rb ?

没有。因为你实际上在控制器中指定了动作,所以在 routes.rb 中你只指定了 routes.

I'll be happy if you point out other places to improve to meet best practice.

这一行:

resources :items, only: [:index, :show, :edit, :update, :new, :create] # better to use %i() notation, eg only: %i(index show edit update new create)

可以写成:

resources :items, except: :destroy

关于您的管理员用户 - 只允许他 destroy,只需检查 current_user 是否为管理员。如果你有更多的,不止一个只允许管理员执行的操作,你可以在控制器中创建 before_action:

before_action :check_admin?, only: %i(destroy another_action)

private

def check_admin?
  # your logic to check, if user is admin
end

您也可能有兴趣浏览 Ruby style guide

即使您没有直接违反 DRY,您通过将单个实体的操作移动到不同的控制器来混淆 REST 架构。您不需要管理员的特定控制器或命名空间 - 您只需要在继续删除操作之前断言用户是管理员。

由于您已经将 admin 列添加到您的设计模型中,您可以将删除操作移动到 ItemsController

def destroy
  if current_user.try(:admin?)

    @item = Item.find(params[:id])
    @item.destroy

    flash[:notice] = 'Item has been deleted.'
  else
    flash[:alert] = 'Only admins can delete items.'
  end
  redirect_to items_path
end

您的路由会更清晰,因为您的管理命名空间将仅用于用户审核。物品的唯一路线是:

  resources :items do
    resources :comments
  end