我希望列出为我的应用程序中的每个页面呈现的部分。例如,当显示 app/tasks/index.html.erb 页面时,我想向用户显示如下内容:
为此页面呈现的部分:
任务/_list.html.erb 任务
/_button.html.erb
任务/_navigation.html.erb
在 Ruby on Rails 中有什么方法可以做到这一点吗?
我希望列出为我的应用程序中的每个页面呈现的部分。例如,当显示 app/tasks/index.html.erb 页面时,我想向用户显示如下内容:
为此页面呈现的部分:
任务/_list.html.erb 任务
/_button.html.erb
任务/_navigation.html.erb
在 Ruby on Rails 中有什么方法可以做到这一点吗?
是的,在 Rails 中完全有办法做到这一点!
正如 bdares 在他的评论中指出的那样,模板渲染的行出现在日志中。但他们最初是如何到达那里的呢?嗯,这与Active Support 中名为LogSubscriber
. 这方面的文档非常详尽:
ActiveSupport::LogSubscriber 是一个对象集,用于使用 ActiveSupport::Notifications,其唯一目的是记录它们。日志订阅者根据给定的命名空间向已注册对象发送通知。
将“Rendered ...”行放在日志中的东西是在 Rails 3.2ActionView::LogSubscriber
中这样定义的。花点时间阅读代码。它很好,很整洁。
这样做是订阅 Rails 中的几个事件,即render_template
,render_partial
和render_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
我把这段代码放在一起是因为它与我们的兴趣非常相关。这是在调用subscribe
对象notifier
。notifier
默认情况下,对象是 ,记住ActiveSupport::Notifications
这一点很重要。Rails 中该类的文档也在 API 中。
当subscribe
被调用时,它通过event
. 这是什么?好吧,它是类中的每一个公共方法。定义子类时LogSubscriber
,它定义了几个公共方法render_template
:render_partial
和render_collection
。这些是将为该日志订阅者订阅的事件。
现在,这与我们的兴趣相关,因为我们将使用相同的东西来订阅视图内的这些事件。第一步是让ActiveSupport::Notfications
我们想要订阅所有部分渲染事件。我们可以通过创建一个新的 inside 来做到这before_filter
一点ApplicationController
:
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
我们订阅的render_partial
事件是action_view
命名空间中的事件,它正是ActionView::LogSubscriber
正在订阅的事件之一。当一个部分被渲染时会发生什么,这个块将被调用并传入一些数据。
event_name
: 事件的名称。
start_at
: 活动开始的时间。
end_at
: 事件结束的时间。
id
:此事件的唯一标识符。
payload
:有关此事件的一些有效负载信息。
当钩子被调用时,它会将identifier
键添加payload
到方法顶部定义的数组中。
然后在视图中,要访问这些列表,您可以执行以下操作:
<%= debug @partial_events %>
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
对于很多像这样的调试信息,看看rails-footnotes
您可能还想查看RailsPanel,它是一个 Chrome 扩展。
这是一篇旧文章,但如果有人发现这很有用,一种非常简单的方法来列出您单击站点时正在使用的所有视图和部分内容是重新启动您的服务器,并且只对“渲染”进行 grep,例如
rails s | grep "Rendered"