使控制器方法可供查看,但略有不同?

时间:2015-05-05 00:40:40

标签: ruby-on-rails ruby-on-rails-4 methods controllers helpers

在我的标题中,我有一个材料页面的链接,我不想让任何人访问,所以我需要在视图中设置条件和在MaterialsController中使用before_filter。

我为视图编写了一个成功的帮助方法,但本着DRY的精神,我想在ApplicationController中只编写一次该方法,并使用helper_method将其提供给视图:

的ApplicationController:

helper_method :user_is_admin_or_teacher_or_student_with_a_class

def user_is_admin_or_teacher_or_student_with_a_class
  if user_signed_in? and ( current_user.admin || current_user.type == "Teacher" || ( (current_user.type == "Student") and current_user.groups.any? ) )
  else redirect_to root_path, alert: "You are not authorised to view the Materials page."
  end
end

这在我的MaterialsController中完美运行:

before_action :user_is_admin_or_teacher_or_student_with_a_class, only: [:index, :show]

它具有预期的效果。

转到帮助方面,我把它放在我的视图中(_header.html.erb):

<% if user_is_admin_or_teacher_or_student_with_a_class %>
  <li><%= link_to "Materials", materials_path %></li>
<% end %>

但是当我尝试在浏览器中加载我的主页时,我得到'此页面有一个重定向循环'浏览器错误。我假设这与控制器方法中的redirect_to root_path命令有关。

我的原始解决方案是从ApplicationController中删除helper_method声明,并在ApplicationHelper中编写一个几乎相同的方法:

def user_is_admin_or_teacher_or_student_with_a_class?
    user_signed_in? and ( current_user.admin || current_user.type == "Teacher" || ( (current_user.type == "Student") and current_user.groups.any? ) )
end

这项工作,但它不是干的。如何干这个并只编写一次方法并在控制器和视图中使用它?

2 个答案:

答案 0 :(得分:2)

我分裂了逻辑。您可以将此方法放在模型中(我假设它是用户):

class User < ActiveRecord::Base
  # ...

  def can_view_materials?
    # note no need for parentheses here if '&&' is used instead of 'and' operator
    admin || type == "Teacher" || type == "Student" && groups.any?
  end

  # ...
end    

然后在MaterialsController

before_action :require_authorization_to_view_materials, only: [:index, :show]

def require_authorization_to_view_materials
  unless user_signed_in? && current_user.can_view_materials?
    redirect_to root_path, alert: "You are not authorised to view the Materials page."
  end
end

最后,在您看来:

<% if user_signed_in? && current_user.can_view_materials? %>
  <li><%= link_to "Materials", materials_path %></li>
<% end %>

这只是你的方法的精致版本。可以通过其他一些更好的方式实现,引入额外的授权逻辑,用户角色等等。但这一切都取决于您的解决方案将会变得多么复杂,以及您是否真的需要它。

注意没有辅助方法来自控制器方法;)

如果您真的想要创建一个控制器/视图常用方法来检查用户权限,可以在ApplicationController中执行此操作:

helper_method :user_can_view_materials?
def user_can_view_materials?
  user_signed_in? && current_user.can_view_materials?
end

MaterialsController

def require_authorization_to_view_materials
  redirect_to root_path, alert: "You are not authorised to view the Materials page." unless user_can_view_materials?
end

并在视野中:

<% if user_can_view_materials? %>
  <li><%= link_to "Materials", materials_path %></li>
<% end %>

答案 1 :(得分:0)

你的root_path指向你正在重定向的同一个控制器。更改重定向路径或根路径

# routes.rb
Rails.application.routes.draw do
  root change_whatevers_here
end

redirect_to change_whatevers_here, alert: "You are not authorised to view the Materials page."