【问题标题】:Ruby on Rails: How do you list the partial paths that are rendered for a page?Ruby on Rails:如何列出为页面呈现的部分路径?
【发布时间】:2013-03-18 02:30:46
【问题描述】:

我希望列出为我的应用程序中的每个页面呈现的部分。例如,当显示 app/tasks/index.html.erb 页面时,我想向用户显示如下内容:

为此页面渲染的部分:

任务/_list.html.erb
任务/_button.html.erb
任务/_navigation.html.erb

在 Ruby on Rails 中有什么方法可以做到这一点吗?

【问题讨论】:

  • 我确信有一种方法,考虑到服务器日志中几乎打印了这些确切的行。我将开始查看中间件堆栈...
  • @bdares:它不在中间件堆栈中。这是一个检测调用。

标签: ruby-on-rails ruby ruby-on-rails-3


【解决方案1】:

是的,在 Rails 中完全有办法做到这一点!

正如 bdares 在他的评论中指出的那样,模板渲染的行出现在日志中。但他们最初是如何到达那里的呢?嗯,这与little something in Active Support called LogSubscriber 有关。这方面的文档非常详尽:

ActiveSupport::LogSubscriber 是一个设置为使用 ActiveSupport::Notifications 的对象,其唯一目的是记录它们。日志订阅者根据给定的命名空间向已注册对象发送通知。

将“Rendered ...”行放入日志中的是ActionView::LogSubscriber,它定义为like this within Rails 3.2。花点时间阅读代码。很好很整洁。

这样做是订阅 Rails 中的几个事件,即render_templaterender_partialrender_collection 方法。它通过调用ActiveSupport::LogSubscriber.attach_to 方法来做到这一点,该方法会将日志订阅者附加到某些事件。这个方法也很有趣,定义如下:

def attach_to(namespace, log_subscriber=new, notifier=ActiveSupport::Notifications)
  log_subscribers << log_subscriber
  @@flushable_loggers = nil

  log_subscriber.public_methods(false).each do |event|
    next if 'call' == event.to_s

    notifier.subscribe("#{event}.#{namespace}", log_subscriber)
  end
end

我已将这段代码放在一行中,因为它与我们的兴趣非常相关。这样做是在 notifier 对象上调用 subscribenotifier 对象默认为 ActiveSupport::Notifications,记住这一点很重要。 documentation for that class in Rails is in the API too

当调用subscribe 时,它通过event 的名称。这是什么?好吧,它是类中的每一个公共方法。在定义LogSubscriber 子类时,它定义了几个公共方法:render_templaterender_partialrender_collection。这些是将为该日志订阅者订阅的事件。


现在,这与我们的兴趣相关,因为我们将使用相同的东西来订阅视图内的这些事件。第一步是让ActiveSupport::Notfications 我们想要订阅all 部分渲染事件。我们可以通过在ApplicationController 中创建一个新的before_filter 来做到这一点:

before_filter :log_partial_events

def log_partial_events
  @partial_events = []
  ActiveSupport::Notifications.subscribe("render_partial.action_view") do |event_name, start_at, end_at, id, payload|
  @partial_events << payload[:identifier]
end

我们订阅的事件是action_view 命名空间中的render_partial 事件,这正是ActionView::LogSubscriber 订阅的事件之一。当一个部分被渲染时会发生什么,这个块将被调用并传入一些数据。

event_name:事件的名称。 start_at:活动开始的时间。 end_at:活动结束的时间。 id:此事件的唯一标识符。 payload:有关此事件的一些有效负载信息。

当调用钩子时,它会将identifier 中的identifier 键添加到方法顶部定义的数组中。

然后在视图中,要访问这些列表,您可以这样做:

<%= debug @partial_events %>

【讨论】:

  • 这太棒了,瑞恩!它工作得很好。感谢您非常清晰的教程和说明! :)
  • 很好的提示,谢谢!建议:您的示例中的块的一些缩进,或方法定义的结束语句,可能会使发生的事情更清楚。
【解决方案2】:

Notification API 中的以下示例应该对您有所帮助:

ActiveSupport::Notifications.subscribe("render") do |*args|
  events << ActiveSupport::Notifications::Event.new(*args)
end

对于您的情况(跟踪渲染的部分),您需要'render_partial.action_view' 通知。您的代码可能如下所示:

class ApplicationController < ActionController::Base
  before_filter :subscribe_to_render

  private
  def subscribe_to_render
    @render_events = []
    ActiveSupport::Notifications.subscribe("render_partial.action_view") do |*args|
      @render_events << ActiveSupport::Notifications::Event.new(*args)
    end
  end
end

无论您想在何处显示此信息,都可以使用此辅助方法:

def display_render_events
  raw(@render_events.map do |event|
    event.payload[:identifier].gsub(/^.*app\/views\//, '')
  end.join('<br/>'))
end

【讨论】:

  • 有趣的是,我们有一个非常相似的方法来解决这个问题。伟大的思想和一切:)
  • @RyanBigg:感谢您的编辑 :) 不同之处在于我必须深入挖掘才能找到它,而您一直都知道它在哪里。
  • 感谢 Pinny 的链接!你和瑞恩很棒:)
  • 我也必须深入研究。我不知道 LogSubscriber,但我之前确实知道 ActiveSupport::Notifications。
【解决方案3】:

如需大量调试信息,请查看rails-footnotes

【讨论】:

    【解决方案4】:

    您可能还想查看RailsPanel,这是一个 Chrome 扩展程序。

    【讨论】:

      【解决方案5】:

      这是一篇旧帖子,但如果有人发现这很有用,那么在您点击网站时列出所有正在使用的视图和部分内容的非常简单的方法是重新启动您的服务器,并且只用 grep 表示“已渲染”,例如

      rails s | grep "Rendered"
      

      【讨论】:

      • 效果很好,很简单!谢谢詹姆斯!!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      相关资源
      最近更新 更多