11

REST API アプリケーションの要求をログに記録しようとしています。ここのように、これにレール通知を使用していますhttp://railscasts.com/episodes/249-notifications-in-rails-3

Rails 通知に関する 1 つの問題を解決する方法がわかりません。

私の初期化コード

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}

ご覧 のとおり :db_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}

:db_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! を使用すると動作しないようです。誰かが理由を教えてもらえますか? ありがとう

4

3 に答える 3

2

わかりました、バグのようです。何が起こっているのか見てみましょう:

まず、コントローラー アクション用の AR railtie と、 cleanup_view_runtime フックを使用して db_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

アプリはコントローラーアクションを呼び出します->いくつかのdbクエリを実行し、いくつかのものをレンダリングするアクション->レンダリングの前後に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

ここにはコードが多すぎるように見えますが、この問題のコールスタックが表示されるはずです。私たちは何も持っていません)。この時点で、ActionView::MissingTemplate をキャッチして、:json と :xml(api_behaviour) をレンダリングするための実装を確認できます。

これで、respond_with の動作はわかりましたが、AR Logger はわかりません. cleanup_view_runtime フックが 2 回呼び出されます: default_renderer に対して (その時点で、テンプレート データが準備され、いくつかの db クエリが呼び出されましたが、レンダリング プロセスで ActionView::MissingTemplate をキャッチします)。

db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
runtime = super # <-- here
db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime

およびapi_behavourの場合(その時点で、すべてのテンプレートデータはレンダリングの準備ができており、dbクエリはありません)

ややこしい説明ですが、参考になれば幸いです:)

于 2013-02-07T22:35:49.610 に答える
0

Rails インストルメンテーションは、Rack の金属レベルでリクエストをラップし、さまざまなメトリックのイベントを記録することで機能します。どちらの場合も、ブロック全体をラップして、標準のインストルメンテーションで追跡する必要があります。

ソースを掘り下げた後にわかる唯一の違いは、save() と save!() の呼び出しです。ActiveRecord の基になるメソッド イベント サブスクリプションの動作が異なるようです。

Respond_with() の例を save と save を使用するように変更してみてください! db_runtime が適切に記録されているかどうかを確認しますか? もしそうなら、それは Rails のバグであり、保存を模倣することで回避できます! 保存を使用する機能。

于 2013-02-02T19:47:00.317 に答える
0

アップデート:

それは簡単ではなく、微調整が必​​要です..

このようなものにフックする独自の Railtie を作成しない限り、そうではありませんActive Recordが、持っているものをコピーするよりも少し複雑Active Recordです...

しかし、これがそれを行う方法です:

1)ログ購読者

2)レイルタイ

3)コントローラーのランタイム

始め方のヒントになれば幸いです。

乾杯!

于 2013-02-07T10:58:48.803 に答える