我正在尝试记录对我的 REST API 应用程序的请求。我为此使用轨道通知,就像这里一样 http://railscasts.com/episodes/249-notifications-in-rails-3
我不明白如何解决轨道通知的一个问题。
我的初始值设定项代码
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, start, finish, id, payload|
p name
p start
p finish
p id
p payload
end
Controller respond section
class PostsController < ApplicationController
# GET /posts
# GET /posts.json
respond_to :json, :html
....
end
控制器创建操作
def create
@post = Post.new(params[:post])
@post.save!
respond_with(@post, :location => nil)
end
控制台输出
"process_action.action_controller"
2013-02-02 20:13:11 +0200
2013-02-02 20:13:11 +0200
"951b8999e9b71d4a8949"
{:controller=>"PostsController", :action=>"create", :params=>{"utf8"=>"✓", "authenticity_token"=>"1WugY9gh6ZCRXjfBTuckye3c9XDvtCqMQ2JdBpCo88s=", "post"=>{"name"=>"post3", "title"=>"post3", "content"=>"post3"}, "commit"=>"Create Post", "action"=>"create", "controller"=>"posts"}, :format=>:html, :method=>"POST", :path=>"/posts", :status=>302, :view_runtime=>nil, :db_runtime=>0}
如您所见:d b_runtime=>0
但是,如果我将控制器操作代码更改为默认基架
def create
@post = Post.new(params[:post])
#@post.save!
#respond_with(@post)
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.json { render json: @post, status: :created, location: @post }
else
format.html { render action: "new" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
我可以看到
"process_action.action_controller"
2013-02-02 20:22:51 +0200
2013-02-02 20:22:51 +0200
"bf2a3173c08a0fd9008e"
{:controller=>"PostsController", :action=>"create", :params=>{"utf8"=>"✓", "authenticity_token"=>"1WugY9gh6ZCRXjfBTuckye3c9XDvtCqMQ2JdBpCo88s=", "post"=>{"name"=>"post3", "title"=>"post3", "content"=>"post3"}, "commit"=>"Create Post", "action"=>"create", "controller"=>"posts"}, :format=>:html, :method=>"POST", :path=>"/posts", :status=>302, :view_runtime=>nil, :db_runtime=>4.727}
:d b_runtime=>4.727
这是什么原因,我如何修复它以使其在第一个示例中工作?谢谢!
UPD
bundle show rails
/Users/admin/.rvm/gems/ruby-1.9.3-p125/gems/rails-3.2.11
rvm current
ruby-1.9.3-p125
UPD2
当我使用respond_with时,它似乎不起作用!有人可以告诉我为什么吗?谢谢
好的,这似乎是一个错误。让我们看看,发生了什么:
首先,我们有用于控制器动作的AR导轨及其通过使用钩子设置db_runtime cleanup_view_runtime
实现def cleanup_view_runtime
if ActiveRecord::Base.connected?
db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
runtime = super
db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
self.db_runtime = db_rt_before_render + db_rt_after_render
runtime - db_rt_after_render
else
super
end
end
应用程序调用控制器操作 ->操作执行一些数据库查询并渲染一些内容 ->渲染之前和之后 AR Logger 保存运行时数据。好。
让我们看看如何工作respond_with
def respond_with(*resources, &block)
raise "In order to use respond_with, first you need to declare the formats your " <<
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
if collector = retrieve_collector_from_mimes(&block)
options = resources.size == 1 ? {} : resources.extract_options!
options[:default_response] = collector.response
(options.delete(:responder) || self.class.responder).call(self, resources, options)
end
end
def self.call(*args)
new(*args).respond
end
def to_format
if get? || !has_errors? || response_overridden?
default_render
else
display_errors
end
rescue ActionView::MissingTemplate => e
api_behavior(e)
end
这里似乎代码太多,但您应该看到此问题的调用堆栈:respond_with -> self.class.responder.response -> self.class.responder.to_format -> default_render -> default_renderer 提出 ActionView::MissingTemplate(因为我们没有任何)。此时,我们可以看到通过捕获ActionView::MissingTemplate来呈现:json和:xml(api_behaviour)的实现。
现在我们知道respond_with是如何工作的,但AR Logger不知道。cleanup_view_runtime钩子被调用了两次:对于default_renderer(当时准备了模板数据并调用了一些数据库查询,但我们在渲染过程中捕获了ActionView::MissingTemplate)
db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
runtime = super # <-- here
db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
和api_behavour(当时所有模板数据都准备好渲染,没有数据库查询)
一些混乱的解释,但我希望它会有所帮助:)
Rails 检测的工作原理是在机架金属级别包装请求并记录不同指标的事件。 在这两种情况下,整个块都应由标准仪器包装和跟踪。
挖掘源代码后我能看到的唯一区别是调用 save() 与 save!(). 看起来 ActiveRecord 中的基础方法事件订阅的行为可能有所不同。
尝试更改您的 respond_with() 示例以使用保存与保存! 看看它是否正确记录了db_runtime? 如果是这样,那就是一个 Rails 错误,您可以通过模仿保存来解决它!使用保存的功能。
更新:
这并不简单,需要一些调整。
除非你编写自己的 Railtie 来像Active Record
一样钩入这个,但它比复制Active Record
拥有的东西要复杂一些......
但这是它是如何做到的:
1) 日志订阅者
2) 导轨
3) 控制器运行时
我希望你得到了如何开始进入它的提示。
干杯!