Freitag, 28. Dezember 2012

Save time per Rails controller query

Ruby On Rails is sooo elaborated. It ships with a lot of optimizations included, like query caching, page caching and so forth. But this is about optimizing a continuous polled controller. Let's assume getting the current state of some machines. Therefore I use a simple cyclic remote link as I described in an earlier post or in CoffeeScript. It queries the controller once per 10 seconds.
The database migrations:
class CreateMachines < ActiveRecord::Migration
  def change
    create_table :machines do |t|
      t.string :name
      t.integer :state_id
      t.timestamps
    end
  end
end
class CreateStates < ActiveRecord::Migration
  def change
    create_table :states do |t|
      t.string :name
    end
  end
end
The models/machine.rb:
class Machine < ActiveRecord::Base
  belongs_to :state
  validates_presence_of :state_id
end
And the models/state.rb:
class State < ActiveRecord::Base
  has_many :machines
end
The controllers/machines_controller.rb:
class MachinesController < ApplicationController
  def index
    respond_to do |format|
      format.html {
        @machines = Machine.includes(:state).order("machines.name ASC")
      }
      format.js {
        @machines = Machine.where("machines.updated_at >= :updated_at",
            { :updated_at => session[:last_status_request] }).includes(:state)
      }
    end
    session[:last_status_request] = Time.now
  end
end
If a simple GET request was received by the MachinesController, it returns all machines including their state and sets the request timestamp in the session initially. They are displayed in the views/machines/index.html.erb:
<ul>
  <% machines.each do |machine| %>
    <li>
      <%= machine.name %>: <span id="<%= dom_id(machine) %>_state"><%= machine.state.name %></span>
    </li>
  <% end %>
</ul>
<%= link_to 'Refresh', machines_path, :remote => true, :class => 'auto_remote' %>
The XMLHTTPRequest triggered by the remote link reaches the format.js part of the MachinesController. Please notice that only those machines are queried, who have been updated since the last status request timestamp. So a lot less machines and their state are queried, instantiated and sent back to the client.
The result is processed in the index.js.erb:
<% @machines.each do |machine| %>
  state = $('#<%= dom_id(machine) %>_state');
  state.text("<%= machine.state.name %>");
<% end %>
This post was more about the conception how to save processing time than an optimized-to-the-bones tutorial. For example you better should render a 304 Not Modified, if no state was updated since the last polling request.
Supported by Ruby on Rails 3.2.8

Keine Kommentare:

Kommentar veröffentlichen