使控制器方法可供查看,但略有不同?
Making controller methods available to view, but slightly differently?
在我的 header 中,我有一个 link 到我不希望任何人访问的材料页面,所以我需要在我的视图中设置一个条件和一个 before_filter 在我的 MaterialsController 中。
我为视图编写了一个成功的辅助方法,但本着 DRY 的精神,我只想在 ApplicationController 中编写该方法一次,并使用 helper_method:[=14 使其对视图可用=]
应用程序控制器:
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 %>
但是当尝试在浏览器中加载我的主页时,我收到 'this page has a redirect loop' 浏览器错误。我认为这与控制器方法中的 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
这行得通,但不是 DRY。我怎样才能把它擦干并只编写一次方法并在控制器和视图中使用它?
您 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."
我会拆分逻辑。你可以把这个方法放在你的模型中(我假设它是用户):
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 %>
这只是您方法的完善版本。可以通过引入额外的授权逻辑、用户角色等其他一些可能更好的方法来实现。但这完全取决于您的解决方案的复杂程度以及您是否真的需要它。
请注意,控制器方法中没有辅助方法 ;)
如果您真的想创建一个 controller/view 通用方法来检查用户权限,您可以在 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 %>
在我的 header 中,我有一个 link 到我不希望任何人访问的材料页面,所以我需要在我的视图中设置一个条件和一个 before_filter 在我的 MaterialsController 中。
我为视图编写了一个成功的辅助方法,但本着 DRY 的精神,我只想在 ApplicationController 中编写该方法一次,并使用 helper_method:[=14 使其对视图可用=]
应用程序控制器:
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 %>
但是当尝试在浏览器中加载我的主页时,我收到 'this page has a redirect loop' 浏览器错误。我认为这与控制器方法中的 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
这行得通,但不是 DRY。我怎样才能把它擦干并只编写一次方法并在控制器和视图中使用它?
您 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."
我会拆分逻辑。你可以把这个方法放在你的模型中(我假设它是用户):
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 %>
这只是您方法的完善版本。可以通过引入额外的授权逻辑、用户角色等其他一些可能更好的方法来实现。但这完全取决于您的解决方案的复杂程度以及您是否真的需要它。
请注意,控制器方法中没有辅助方法 ;)
如果您真的想创建一个 controller/view 通用方法来检查用户权限,您可以在 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 %>