Ruby on rails Rails:在运行时为每个请求动态包含帮助程序

Ruby on rails Rails:在运行时为每个请求动态包含帮助程序,ruby-on-rails,ruby-on-rails-4,actioncontroller,Ruby On Rails,Ruby On Rails 4,Actioncontroller,我的应用程序是有固定用户和管理员的。它有几个显示小部件的渲染帮助程序: module ApplicationHelper def widget "widget" end end 对于管理员,有以下小部件的扩展版本: module AdminHelper def widget "admin-widget" end end 默认情况下,通过config.action\u controller.include\u all\u helpers=false将应用程序配置

我的应用程序是有固定用户和管理员的。它有几个显示小部件的渲染帮助程序:

module ApplicationHelper
  def widget
    "widget"
  end
end
对于管理员,有以下小部件的扩展版本:

module AdminHelper
  def widget
    "admin-widget"
  end
end
默认情况下,通过
config.action\u controller.include\u all\u helpers=false将应用程序配置为不包括所有帮助程序

当管理员查看一个页面(同一个控制器、同一个视图模板)时,我希望通过使用其AdminHelper版本重载帮助程序来呈现该页面的扩展版本。如果当前登录的用户是管理员,如何在每个请求的基础上使用AdminHelper重载ApplicationHelper

我试过了

class ApplicationController < ActionController::Base  
  before_action :include_backend_helpers

    protected

  def include_backend_helpers
    self.class.helper "pica/backend" if admin_signed_in?
  end
end
class ApplicationController

但是,除非在请求之间重新加载ApplicationController,否则这不起作用。

尝试动态加载代码以覆盖小部件是错误的做法。相反,
小部件
方法应该根据请求决定显示哪个版本。在我们研究一些方法之前,让我们解释一下为什么模块重写不起作用


ApplicationController
在Rails应用程序启动时加载。这将自动包括
ApplicationHelper
模块,该模块定义了
小部件
方法。由于
config.action\u controller.include\u all\u helpers
设置,未加载
AdminHelper
,Rails将其设置为
false
仅加载与控制器同名的帮助器

当普通用户调用
widget
方法时,返回字符串
“widget”
。但是一旦管理员访问该站点,
include\u backend\u helpers
回调将加载您的
AdminHelper
模块,覆盖
小部件
方法。管理员得到返回的字符串
“admin widget”
,但将来每个访问该站点的访问者都会得到返回!
小部件
方法没有根据用户类型进行区分

您可以通过在每次请求后重新加载
ApplicationController
来解决此问题,但这需要时间,而且会导致性能下降。但这似乎是一个充满困难的方法。您还可以尝试在每次请求时重新加载帮助程序:

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部分使用类似的方法-您可以有一个
\u navigation.html.erb
部分,其中包括
\u user\u navigation.html.erb
\u admin\u navigation.html.erb
基于
admin\u登录?
。您的视图包含“”,不需要担心内部细节


如果您有足够多的代码,上面的内容开始变得笨拙,那么您应该看看。这是一个使构建封装显示组件(控制器逻辑和视图代码的组合)更容易的宝石。

感谢您提供详细的答案!我不希望检查每个小部件中的用户角色-这是相当多余的对于我的视图和部分,我只要
在管理员登录时预先设置视图路径?
——这样我就可以在必要时逐个覆盖它们;我所缺少的只是一种处理助手的类似优雅方法。如果你有几十个组件,我会尝试找到一些我可以定义的东西然后,在基类中,我将执行类似于
m=“admin#{method}”的操作,返回self.call(m)(如果admin#u登录?&&self.respond(m)
在它里面。这似乎是你可以很好地处理的事情。我会尝试一下这个想法,谢谢。对于这个项目,我已经看过了Cells,出于概念上的原因,放弃了它,但我会再试一次。