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

时间:2015-07-31 04:58:12

标签: ruby authentication devise dry ruby-on-rails-4.2

当我正在阅读Rails 4 in Action时,我正在尝试实现自己的应用程序,因此它与书中的内容不同。 该书的相应提交是Section 7.2.3: Only admins can create or delete projects

就我而言,管理员只能删除该项item对应于图书中的project。)。

我的回购https://github.com/tenzan/shop并部署了http://ichiba-demo.herokuapp.com/

我想申请的规则是:

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

    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. 当我在2个地方指定操作时,即routes.rbcontrollers/items_controllers.rb
    4. ,我是否违反DRY概念?

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

      PS:主题可能含糊不清,请随时编辑。

2 个答案:

答案 0 :(得分:2)

  

我是否必须在routes.rb中指定操作,就像我已经拥有的那样   指定谁可以在相应的控制器中使用哪些操作?

是。例如,如果您在items_controller.rb控制器中只有一个操作(假设show),则离开

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

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

  

当我在2个地方指定行动时,我是否违反DRY概念,即   在routes.rb和controllers / items_controllers.rb?

没有。由于您实际在控制器中指定了操作,因此在routes.rb中您只需指定路由

  

如果你指出其他地方需要改进以达到最佳状态,我会很高兴的   实践。

这一行:

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是否为admin。如果您只有一个允许仅由admin执行的操作,则可以在控制器中创建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感兴趣。

答案 1 :(得分:1)

即使您没有直接违反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