我的Rails API中有一系列控制器,它们非常相似-它们仅具有基本的CRUD动作,并且所存储的基础数据的形状不同。
我实现授权的方式,在每个控制器中,我都有一些before_action调用,这些调用在给定的CRUD操作的适当级别上检查权限-这些权限检查实际上是重复的,除了每个权限检查使用不同的名称实例变量-例如也许有人会说
before_action -> { is_app_admin?(@app_name) } #where @app_name is the actual name of the app.
现在,如果控制器本身可以采用某种参数,则可以将它们放在ApiController中的检查之前,而不必重复它们。或者,我可以将所有控制器中的变量名称更改为类似@app_name的通用名称,但是在控制器本身中会导致代码可读性降低。
在这种情况下,是否有抽象重复代码的标准方法?
答案 0 :(得分:3)
请记住,before_action
不是特殊的语法,它只是一个与其他方法一样的类方法。这意味着您可以编写一个调用before_action
的类方法:
def self.ensure_app_admin_in(var)
before_action ->{ is_app_admin?(instance_variable_get(var)) }
end
在模块中添加控制器问题,ApplicationController
或方便的地方,然后在控制器中说:
class Controller1
ensure_app_admin_in :@app_name
#...
end
class Controller2
ensure_app_admin_in :@my_other_app_name
#...
end
答案 1 :(得分:2)
在这种情况下,是否有抽象重复代码的标准方法?
是的。好吧,抽象。在具有有意义名称的方法中隐藏该不同名称。例如,如果您具有以下条件:
class Controller1
before_action -> { is_app_admin?(@app_name) }
end
class Controller2
before_action -> { is_app_admin?(@my_other_app_name) }
end
这就是您可以做的:
class Controller1
before_action -> { is_app_admin?(app_name_for_authorization) }
private
def app_name_for_authorization
@app_name
end
end
class Controller2
before_action -> { is_app_admin?(app_name_for_authorization) }
private
def app_name_for_authorization
@my_other_app_name
end
end
之前的动作现在是相同的,您可以将其拉到父类或提取为关注点。
答案 2 :(得分:0)
您可以创建一个模块并将类似的控制器放入其中,并使用一个类似于application_controller的base_controller来执行您的before_actions,只有从其继承的控制器才能使用它们。
例如,如果您有一些管理控制器:
class Admin::BaseController < ApplicationController
before_action :authorize_admin!
def authorize_admin!
redirect_to root_path unless user.admin?
end
end
class Admin::UsersController < Admin::BaseController
def index
end
end
然后在您的路由中,您可以命名空间,或将模块添加到路由中,如下所示:
resources :users, module: 'admin'
然后将您的管理控制器放在app/controllers/admin
中,并将您的视图放在app/views/admin/users
中。