Подтвердить что ты не робот

Уведомления об активах rails - неправильное время выполнения db

Я пытаюсь регистрировать запросы для моего приложения REST API. Я использую для этого рельсовые уведомления, например здесь http://railscasts.com/episodes/249-notifications-in-rails-3

Я не могу понять, как решить одну проблему с уведомлениями rails.

мой код инициализатора

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

Кажется, что это не работает, когда я использую response_with! Может кто-нибудь сказать мне, почему? Благодаря

4b9b3361

Ответ 1

Хорошо, это похоже на ошибку. Посмотрим, что происходит:

Прежде всего, у нас есть AR railtie для действия контроллера и его реализация для установки db_runtime с помощью hookup_view_runtime hook

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 сохраняет данные времени выполнения. Хорошо.

Посмотрим, как работает response_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

Здесь, похоже, слишком много кода, но вы должны увидеть столбец для этой проблемы: reply_with → self.class.responder.respond → self.class.responder.to_format → default_render → default_renderer raise ActionView:: MissingTemplate (потому что у нас их нет). На данный момент мы можем увидеть реализацию для рендеринга: json и: xml (api_behaviour) через catching ActionView:: MissingTemplate.

Теперь мы знаем, как работает response_with, но AR Logger не знает.. cleanup_view_runtime hook вызывается дважды: для 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)

Некоторые беспорядочные объяснения, но я надеюсь, что это будет полезно:)

Ответ 2

Инструмент Rails работает, обертывая запрос на уровне металла стойки и записывая события для разных показателей. В обоих случаях весь блок должен быть обернут и отслежен стандартным прибором.

Единственное различие, которое я могу видеть после того, как выкалывание в исходный код вызывает вызов save() vs. save!(). Похоже, что подписка на базовые методы в ActiveRecord может вести себя по-другому.

Попробуйте изменить пример response_with(), чтобы использовать save и save! и посмотрите, правильно ли он записывает db_runtime? Если да, то ошибка Rails, и вы можете обойти ее, подражая сохранению! функции с сохранением.

Ответ 3

UPDATE:

Это не просто и требует некоторой настройки..

Нет, если вы не написали свой собственный Railtie, чтобы подключиться к нему как Active Record, но он немного сложнее, чем копировать то, что Active Record имеет...

Но вот как это делается:

1) Абонент журнала

2) Railtie

3) Время выполнения контроллера

Я надеюсь, что у вас есть намек на то, как начать в нее входить.

Ура!