2014-10-11 57 views
0

我的Rails应用程序最多可以有一个管理员,但任意数量的用户。如何确保最多一个管理员在轨道应用程序设计?

我正在使用设计宝石,并且正在使用用户模型和布尔管理字段来确定用户是否为管理员。

我想确保在应用程序实例上至多存在一个管理员。更具体地说,我想确保如果网站上已存在管理员,则无法添加其他管理员。

我目前有一个弱的解决方案,覆盖用户/注册/新设计视图,只有在数据库中没有管理员(否则只有用户可以注册)的情况下允许用户注册为管理员。

<!-- in /users/registrations/new.html.erb --> 
<% if admin_exists? %> 
    <h2>User Sign up</h2> 
<% else %> 
    <h2>Admin Sign up</h2> 
<% end %> 

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> 

    ... 

    <% unless admin_exists? %> 
     <%= f.hidden_field :admin, value: true%> 
    <% end %> 

    ... 

我需要比这更强的检查,所以我认为以下几点:

  1. 验证:我不希望使用ActiveRecord的验证,因为有验证时跳过场景,允许多个管理员将是灾难性的。

  2. before_action:基于this方法,它向控制器添加过滤器,我可以添加一个检查,以防止在创建和更新期间添加管理员。

  3. 使用触发器和存储的特效(啊!)

更新1:

  • 非常类似于图2,在ApplicationController中使用的检查如下:

    class ApplicationController < ActionController::Base 
        before_action :check_at_most_one_admin_on_writes, if: :devise_controller?, 
        only: [:create, :update] 
    
        private 
        def check_at_most_one_admin_on_user_writes 
         if(admin_exists && params.has_key?(:admin) && params[:admin] == true) 
         flash[:alert] = "Site administrator already exists" 
         redirect_to :back 
         end 
        end 
    end 
    
  • 更新2: (4)不起作用。可能需要直接覆盖RegistrationsController。

    我还不确定这些功能是否足够强大,足以保证两个管理员永远不会无意中创建。在多达一个管理约束下执行此操作的好方法是什么?

    更新3:(基于下面的评论)

    的应用程序是一个个人网站的框架,每个客户下载,部署到主控器,然后立即配置自己作为管理员。所以,我不能通过种子等预先创建管理员。

    +0

    你不应该允许任何提升权限的字段(比如'role'或者'admin')可以从表单访问,使用种子创建你的admin用户,并且不允许删除它们,你可以防止删除,或保存在模型中的回调(如果由于某种原因,你故意跳过验证) – Pavling 2014-10-11 16:09:35

    +0

    @Pavling谢谢。rails应用程序是一个个人网站框架,每个客户下载,部署到一个主机,然后立即配置为一个自己因此,我不能通过种子等方式预先创建管理员 – Anand 2014-10-11 16:11:54

    +1

    您可以拥有一个生成管理员的rake任务...但是如果您坚持按照您的计划方式执行此任务,请拥有一个单独的控制器和路由用于创建管理员用户(与正常Devise路线分开)。您仍然可以继承Devise控制器,但在AdminsController中您可以设置admi n属性并通过将块传递给'super'来检查冲突。 – Pavling 2014-10-12 08:28:44

    回答

    1

    假设你的布尔属性映射到允许null的数据库列,那么你可以添加一个唯一的索引。然后,对于管理员用户,该列设置为1,并且该值只允许一行。然后您需要确保普通用户将列设置为未设置(保留为空),因为尝试将多列设置为0的列将由于唯一索引而失败。这意味着数据库本身将强制要求只有一个管理员用户。它也避免了触发器或存储过程的需要。

    您通常不能依靠应用中的ruby代码来通过验证来强制实施约束,因为它们不能提供完整性保证数据库可以(例如具有多个线程/进程的情况)。

    相关问题