5秒後に一度だけ処理する。

CSVサーバーでは、一定時間経過したら、自動的にメッセージを消すために、periodically_call_remoteを利用している。でも、これを使うとあまり調子が良くない...。現状、10秒に1回、2秒間かけてビジュアルエフェクトを処理するように指定しているので、これが結構な負荷になっているみたい...。(MacBookが熱い!)
やりたいことは、一定時間経過後、メッセージを消すだけなので、今のように繰り返す必要は無いのだ。一度だけ処理して、その後、繰り返さないperiodically_call_remoteが欲しいのだが、そのようなオプション指定は出来ないようだ。そこで別な方法を考えてみると、page.delayメソッドのことを思い出した。page.delay(10){処理}のように書けば、10秒後にブロックの中を実行してくれるのだ!以下のように変更した。

app/views/layouts/_flash.rhtml
ビュー(レイアウトでフラッシュメッセージを描画する部分)
  • フラッシュメッセージを表示したら、常にcheck_flash_timerを呼び出すようにした。
<div id="flash">
<% for name in [:notice, :warning, :message] %>
<% if flash[name] %>
<br />
<div class="flash">
  <%= "<p style=\"color: green\">#{flash[name]}</p>" %>
  <% flash[name] = nil %>
</div>
<% end %>
<% end %>
<%= javascript_tag remote_function(:url=>{:action=>:check_flash_timer}) %>
</div>
app/controllers/application.rb
コントローラー
  • p.delay(5) do 処理 endブロック内は処理されても、実行は5秒後になる。
require 'login_engine'
class ApplicationController < ActionController::Base
...(途中省略)...
  # メッセージが表示される時はcheck_flash_timerが呼び出されるので、
  # user_engineはそれを直前に実行したアクションとして認識してしまう。
  # そのため、権限がない場合、user_engineのユーザー認証機能によって、
  # 常にcheck_flash_timerへリダイレクトする、という困った状態になる。
  # if request.xhr?によって、AJAX requestかどうか判断し、上記の困った状態を回避している。
  # - AJAX呼出し(remote_functionによる呼び出し)なら、5秒後にフラッシュメッセージを非表示にする。
  # - さもなければ(user_engineによる直前のアクションへのリダイレクト)、さらに/csvs/listへリダイレクトする。
  def check_flash_timer
    if request.xhr?
      render :update do |p|
        p.delay(5) do
          p.visual_effect(:DropOut, "flash", :duration => 2)
        end
      end
    else
      redirect_to :controller=>'csvs', :action=>'list'
    end
  end
end


これで、MacBookの熱さが、多少緩和された。