我的应用有常规用户和管理员。它有一些显示小部件的渲染助手:
module ApplicationHelper
def widget
"widget"
end
end
对于管理员,这些小部件有扩展版本:
module AdminHelper
def widget
"admin-widget"
end
end
默认情况下,应用程序配置为不包括所有帮助程序{.1}}。
当管理员查看页面 - 同一个控制器,相同的视图模板 - 时,我想通过使用AdminHelper版本重载帮助程序来呈现它的扩展版本。如果当前登录的用户是管理员,如何在每个请求的基础上使用AdminHelper重载ApplicationHelper?
我试过了
config.action_controller.include_all_helpers = false
但除非在请求之间重新加载ApplicationController,否则这不起作用。
答案 0 :(得分:2)
尝试动态加载代码以覆盖窗口小部件是错误的方法。相反,widget
方法应决定在逐个请求的基础上显示哪个版本。在我们看一些方法之前,让我们解释为什么模块覆盖不起作用。
ApplicationController
。这会自动包含ApplicationHelper
模块,该模块定义widget
方法。由于AdminHelper
设置,未加载config.action_controller.include_all_helpers
- 通过将其设置为false
Rails将仅加载与控制器同名的帮助程序。
当普通用户调用widget
方法时,将返回字符串"widget"
。但管理员访问网站后 include_backend_helpers
回调会加载您的AdminHelper
模块,覆盖widget
方法。管理员获取了返回的字符串"admin-widget"
- 但该网站的每个未来访问者也是如此! widget
方法不基于用户类型进行区分。
你可以通过在每个请求之后重新加载ApplicationController
来解决这个问题,但这需要时间并且会使性能陷入困境。你might be able to unload the module,但这似乎是一种充满困难的方法。您还可以尝试在每个请求上重新加载帮助程序:
def include_backend_helpers
if admin_signed_in?
self.class.helper "admin/backend"
else
self.class.helper "user/backend"
end
end
但我不确定这会起作用,我不会推荐它。
相反,似乎小部件的工作是决定什么是适合显示。例如,如果这是一个导航组件,它应该足够智能,只显示管理员链接。您仍然可以将其分解为单独的方法:
module ApplicationHelper
def widget
if admin_signed_in?
user_widget
else
admin_widget
end
end
private
def user_widget
"widget"
end
def admin_widget
"admin-widget"
end
end
您可以对Rails部分使用类似的方法 - 您可以使用基于_navigation.html.erb
的{{1}}部分_user_navigation.html.erb
或_admin_navigation.html.erb
。您的视图包含“<%= render”导航“%>”,并且不会担心内部细节。
如果您有足够的代码使上述内容开始变得难以处理,那么您应该查看Cells for Rails。它是一个宝石,可以更容易地构建封装的显示组件 - 控制器逻辑和视图代码的组合。