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

时间:2021-09-09 06:53:44

In my header, I have a link to a Materials page that I don't want just anyone to access, so I need a condition set in my view and a before_filter in my MaterialsController.

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

I wrote a successful helper method for the view, but in the spirit of DRY, I wanted to write that method just once in the ApplicationController and make it available to the view using helper_method:

我为视图编写了一个成功的帮助方法,但是在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

This worked perfectly in my MaterialsController:

这在我的MaterialsController中完美运行:

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

It has the desired effect.

它具有预期的效果。

Moving onto the helper side of things, I placed this in my view (_header.html.erb):

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

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

But when trying to load my homepage in the browser, I get the 'this page has a redirect loop' browser error. I assume this is to do with the redirect_to root_path command in the controller method.

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

My crude solution was to remove the helper_method declaration from ApplicationController and write an almost identical method in ApplicationHelper:

我的原始解决方案是从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

Of this works, but it's not DRY. How can I DRY this up and write the method just once and use it in Controllers and in Views?

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

2 个解决方案

#1


I'd split the logic. You could put this method in your model (I assume it's the user):

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

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    

then in MaterialsController:

然后在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

Finally, in your view:

最后,在您看来:

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

It's just polished version of your approach. Could be achieved in few other, maybe better ways, introducing additional authorization logic, user roles, etc. But it all depends how complex your solution is going to be and if you'll really need it.

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

Note no helper methods made from controller methods ;)

注意没有由控制器方法制作的辅助方法;)

If you REALLY want to make a controller/view common method to check user permissions you could do this in ApplicationController:

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

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

and in MaterialsController:

并在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

and in view:

在视野中:

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

#2


You're root_path points to the same controller you're redirecting from. Change the redirection path or your root path

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

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

or

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

#1


I'd split the logic. You could put this method in your model (I assume it's the user):

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

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    

then in MaterialsController:

然后在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

Finally, in your view:

最后,在您看来:

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

It's just polished version of your approach. Could be achieved in few other, maybe better ways, introducing additional authorization logic, user roles, etc. But it all depends how complex your solution is going to be and if you'll really need it.

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

Note no helper methods made from controller methods ;)

注意没有由控制器方法制作的辅助方法;)

If you REALLY want to make a controller/view common method to check user permissions you could do this in ApplicationController:

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

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

and in MaterialsController:

并在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

and in view:

在视野中:

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

#2


You're root_path points to the same controller you're redirecting from. Change the redirection path or your root path

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

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

or

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