ruby-on-rails – 如何在Rails 4上为用户角色隐藏部分视图

我试图隐藏部分视图,具体取决于用户角色.

所以,假设我只希望管理员能够销毁产品.除了控制器中用于防止常规用户销毁记录的代码外,我还会在视图中执行以下操作:

<% if current_user.admin? %>
  <%= link_to 'Delete',product,method: :delete %>
<% end %>

前面的代码有效,但它容易出现遗漏错误,这可能导致普通用户看到不允许执行的操作的链接.

此外,如果我稍后决定新角色(例如“主持人”)可以删除产品,我将不得不找到显示删除链接的视图并添加允许主持人查看它的逻辑.

如果有许多模型只能由管理员用户删除(例如促销,用户),那么所有ifs的维护将非常具有挑战性.

有没有更好的方法呢?也许使用帮手,或类似的东西?我正在寻找像这样的东西:

<%= destroy_link 'Delete',product %> # Only admins can see it
<%= edit_link 'Edit',promotion %> # Again,only admins see this link
<%= show_link 'Show',comment %> # Everyone sees this one

我发现这两个问题与我的相似,但没有人回答我的问题:

Show and hide based on user role in rails

Ruby on Rails (3) hiding parts of the view

解决方法

使用CanCan和Role gems,还需要一种方法来检查路由并查看“current_user”是否有权根据其角色访问该路由 – 然后根据该角色显示/隐藏.

这样可以节省用户单击事物并告知他们无法看到它 – 或者我们必须编写每个项目“if”逻辑指定哪些角色可以查看哪些列表项(客户将定期更改,因为角色已更改/改进) )在一个菜单中的每个链接周围(考虑一个引导菜单,其中50个项目嵌套在具有html格式的组中等),这是疯狂的.

如果我们必须在每个菜单项周围放置if-logic,那么让我们通过检查我们在Ability文件中定义的角色/权限,为每个项目使用完全相同的逻辑.

但是在我们的菜单列表中,我们有路由助手 – 而不是“控制器/方法”信息,那么如何测试用户是否能够点击为每个链接中的“路径”指定的控制器操作?

获取路径的控制器和方法(动作)(我的示例使用’users_path’route-helper)…

Rails.application.routes.recognize_path(app.users_path)
        => {:controller=>"users",:action=>"index"}

获取控制器名称

Rails.application.routes.recognize_path(app.users_path)[:controller]
        => "users"

能力使用模型进行细分,因此从控制器名称转换为模型(假设使用认命名)…

Rails.application.routes.recognize_path(app.users_path)[:controller].classify
        => "User"

获取动作名称

Rails.application.routes.recognize_path(app.users_path)[:action]
        => "index"

既然“可以?”对于每个菜单项,我们得到的方法需要一个符号表示动作,而常量表示模型:

path_hash = Rails.application.routes.recognize_path(app.users_path)
    model = path_hash[:controller].classify.constantize
    action = path_hash[:action].to_sym

然后使用我们现有的Abilty系统来检查current_user是否可以访问它,我们必须将动作作为符号传递,并将模型作为常量传递,所以……

<% if can? action model %>
        <%= link_to "Users List",users_path %>
    <% end %>

现在,我们可以更改谁可以从Ability文件中看到此资源和链接,而不会再次弄乱菜单.但是为了使这个更清洁,我在app-controller中为每个菜单提取了查找:

def get_path_parts(path)
  path_hash = Rails.application.routes.recognize_path(path)
  model_name = path_hash[:controller].classify.constantize
  action_name = path_hash[:action].to_sym
  return [model_name,action_name]
end
helper_method :get_path_parts

…所以我可以在视图中执行此操作(为了简单起见,我从链接中取出了所有html格式,这里):

<% path_parts = get_path_parts(users_path); if can?(path_parts[1],path_parts[0]) %>
    <%= link_to "Users Listing",users_path %>
<% end %>

…并且为了使这不是整天打字这些每菜单项if-wraps,我使用正则表达式查找/替换捕获和通配符来包围菜单项列表中的每个列表项一次传递.

它远非理想,我可以做更多的事情来使它变得更好,但我没有空余时间来编写角色/ CanCan系统的其余部分.我希望这部分可以帮助别人.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...