2015-05-05 25 views
2

在我的頭文件中,我有一個指向Materials頁面的鏈接,我不想讓任何人訪問它,所以我需要在我的視圖中設置一個條件,在我的MaterialsController中需要一個before_filter。使控制器方法可以查看,但稍有不同?

我寫的視圖一個成功的輔助方法,但在乾燥的精神,我想寫的方法只有一次在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 

這個作品,但它不幹燥。我該如何幹起來,只寫一次該方法,並在控制器和視圖中使用它?

+0

您可以將通用代碼放入您的模型中,然後在您的'before_action'和您的視圖中調用。 –

回答

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 %> 
+0

非常好。一個問題 - 爲什麼你會將代碼放在'ApplicationController'而不是'MaterialsController'中? –

+0

你的意思是'require_authorization_to_view_materials'方法?當然你可以把它放在'MaterialsController'中。 'user_can_view_materials?'應該在'ApplicationController'中,但是,因爲它在'_header'部分中使用,我認爲它總是被渲染,整個頁面的導航等等(我希望它是有意義的;) –

+0

我已經更新這個例子。謝謝@steveklein –

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." 
相關問題