0

I have a Rails 3.2.14 app where I have calls, calls have units, units have statuses, and calls times in the model such as in_service_time.

I'm trying to write a controller action called in_service which updates the unit's status to "In Service" and time stamps call.in_service_time to Time.zone.now and does all of this via put remote (Ajax).

What I've written so far seems to work by updating the unit status and time stamping the call.in_service_time. But using :remote => true doesn't render the partials as I've specified in the in_service action. I have to wait for the screen to refresh via a getScript call in my index.html.erb for the call status to update. If I use :remote => false it reloads the page immediately without problems. If I use the :remote => true I also throw an exception in my development.log for NihlClass.

Below are excerpts of the code in question, the full code can be found here to keep things easier to read: full code

index.html.erb

<div id="active">
  <%= render "assigned_calls" %>
</div>

<div id="inactive">
  <%= render "unassigned_calls" %>
</div>


<script>
  $(function() {
    setInterval(function(){
      $.getScript("/calls").fail(function(jqxhr, settings, exception) {
        window.location = "/users/sign_in?duplicate_session=true";
      });
    }, 10000);
  });
</script>

index.js.erb

$("#active").html("<%= escape_javascript render("assigned_calls") %>");
$("#inactive").html("<%= escape_javascript render("unassigned_calls") %>");

routes.rb excerpt

resources :calls do
    member do
      post 'close'
      post 'cancel'
      post 'note'
      get 'opencall'
      get  'new_return'
      get 'duplicate_call'
      get 'edit_times'
      put 'update_billing'
      post 'dispatch_call'
      put 'en_route'
      put 'on_scene'
      put 'to_hospital'
      put 'at_hospital'
      put 'in_service'
    end

calls_controller.rb excerpt

def in_service
    @call = Call.find(params[:id])
    @unit = @call.units.first
    @call.update_attributes(in_service_time: Time.zone.now)
    @call.save
    @unit.status = Status.find_by_unit_status("In Service")
    @unit.save
    respond_to do |format|
       format.html { redirect_to calls_url }
       format.js { render "index" }
     end
   end

_assigned_calls.html.erb

<div class="page-header">
  <span class="badge badge-important"><%= @unassigned.count %></span> <strong>Unassigned calls</strong>
  <span class="badge badge-info"><%= @assigned.count %></span> <strong>Active calls</strong>
  <span class="badge badge-warning"><%= @scheduled.count %></span> <strong>Scheduled calls</strong>
  <%= render "search" %>
  <h2>Active Calls</h2>



</div>

<% @assigned.each do |call| %>
  <div class="widget">
    <div class="widget-header">
      <div class="pull-right">

        <%= link_to 'View', call, :class => 'btn btn-close'%>
        <% if dispatch? %>
        <%= link_to 'Edit', edit_call_path(call), :class => 'btn btn-close'%>
        <%= link_to 'Close', close_call_path(call), confirm: 'Are you sure you want to close the call?', :method => :post, :class => 'btn btn-danger' %>
        <%= link_to 'Cancel', cancel_call_path(call), confirm: 'Are you sure you want to cancel the call?', :method => :post, :class => 'btn btn-warning' %>
        <% end %>
      </div>
      <i class="icon-phone"></i>
      <h3><%= link_to call.incident_number, call %> <span><%= status(call) %></span></h3> 
      <% if call.traffic_type == "Emergency" %>
      <span class="badge badge-important"><%= call.traffic_type %></span>
      <% else %>
      <span class="badge badge-info"><%= call.traffic_type %></span>
     <% end %>
    </div>

    <div class="widget-content">
      <div class="row">
        <div class="span3">
         <h4>Patient Name: <small><%= call.patient_name %></small></h4>
          <div class="large-display">
            <% if call.call_status == "open" %>
            <div class="large <%= elapsed_overdue(call.elapsed_time) %>"><%= TimeFormatter.format_time(call.elapsed_time)%></div>
            <div class="small">Elapsed Time</div>
            <% else %>
              <% if call.closed_at? %>
            <div class="large <%= elapsed_overdue(call.run_time) %>"><%= TimeFormatter.format_time(call.run_time)%></div>
            <div class="small">Run Time</div>
              <% end %>
            <% end %>
          </div>
        </div>

        <div class="span2">
          <address>
            <strong><%= transferred_from(call) %></strong><br>
            <%= transferred_from_address(call) %>
          </address>
        </div>

        <div class="span1"><i class="icon-arrow-right dim"></i></div>

        <div class="span2">
          <address>
            <strong><%= transferred_to(call) %></strong><br>
            <%= transferred_to_address(call) %>
          </address>
        </div>

        <div class="span3">
          <% if call.service_level.level_of_service == "WC" %>
          <div class="left-icon dim"><i class="icon-user"></i></div>
          <% else %>
          <div class="left-icon dim"><i class="icon-ambulance"></i></div>
          <% end %>
          Assigned to <strong>Unit <%= call.units.map(&:unit_name).join(", ") %></strong><br />
          <% call.units.each do |unit| %>
            <div class="<%= set_status(unit.status) %>"><%= unit_status(unit) %></div>
          <% end %>
        </div>
      </div>

      <hr />

      <div class="row">
        <div class="span2">
          <div class="large-display">
            <div class="medium <%= transfer_due(call.transfer_date) %>"><%= call.transfer_date.strftime("%m/%d/%y %H:%M") %></div>
            <div class="small">Transfer Date</div>
          </div>
        </div>

        <div class="span1">
          <div class="large-display">
            <div class="small"><%= call.nature.try(:determinant) %></div>
            <div class="small">Nature</div>
          </div>
        </div>


        <div class="span5">
          <% if call.unit_ids.present? %>
            <div class="large-display">
              <div class="progress progress-striped"><%= progress_bar(call) %></div>
              <div class="small"><%= call.units.first.status.unit_status %></div>
              <div><%= link_to 'En Route', en_route_call_path(call), :class => 'btn btn-warning btn-medium', :method => :put, :remote => true %><%= link_to 'On Scene', on_scene_call_path(call), :class => 'btn btn-primary btn-medium', :method => :put, :remote => true %><%= link_to 'To Hospital', to_hospital_call_path(call), :class => 'btn btn-warning btn-medium', :method => :put, :remote => true %><%= link_to 'At Hospital', at_hospital_call_path(call), :class => 'btn btn-danger btn-medium', :method => :put, :remote => true %><%= link_to 'In Service', in_service_call_path(call), :class => 'btn btn-success btn-medium', :method => :put, :remote => true %></div>
              <div>ER: <%= call.en_route_time.try(:strftime, "%m/%d/%y-%k:%M") %> OS: <%= call.on_scene_time.try(:strftime, "%m/%d/%y-%k:%M") %> TO: <%= call.to_hospital_time.try(:strftime, "%m/%d/%y-%k:%M") %> AT: <%= call.at_hospital_time.try(:strftime, "%m/%d/%y-%k:%M") %>  IS: <%= call.in_service_time.try(:strftime, "%m/%d/%y-%k:%M") %></div>
            </div>
          <% end %>
        </div>



        <div class="span3">
          <div class="left-icon dim"><i class="icon-user"></i></div>
          <%= render partial: "medics_for_call", locals: {call: call} %>
        </div>
      </div>
    </div>
  </div>
<% end %>

development.log excerpt

NoMethodError - undefined method `count' for nil:NilClass:
  app/views/calls/_assigned_calls.html.erb:2:in `_app_views_calls__assigned_calls_html_erb___2549181816739942207_70125964034780'
nulltek
  • 3,247
  • 9
  • 44
  • 94

1 Answers1

0

You're never setting @unassigned in your in_service action. So sending count to it throws an exception.

Rendering an action's view (render "index") from a different action does not execute the action's controller code.

EDIT: How to make it DRY:

class CallsController < ApplicationController
  ...

  def index
    setup_scheduling_variables
    @units = Unit.order("unit_name")
    @overdue = @assigned.select{|call| call.elapsed_time > 3600}
    @inservice = Unit.in_service
  end


  def in_service
    ...
    respond_to do |format|
       format.html { redirect_to calls_url }
       format.js do 
         setup_scheduling_variables
         render "index" 
       end
     end
   end

private

  def setup_scheduling_variables
    @assigned = params[:search].present? ? Call.search(params[:search]) : Call.assigned_calls.until_end_of_day.order("transfer_date ASC")
    @unassigned = Call.unassigned_calls.until_end_of_day
    @scheduled = Call.scheduled_calls
  end
supermoogle
  • 1,207
  • 10
  • 7
  • You're right! I was writing from memory and had an example of this in an old controller I haven't touched in a year. I ended up having to add the instance variables of assigned, unassigned, and scheduled that were part of the index action to get rid of the exception. Now the page refreshes via Ajax/JS and no exceptions are thrown. Thanks for helping me to remember convention. It's been a while since I've touched code. Newb mistake. :( – nulltek Jan 15 '14 at 23:06
  • In my controller action, "in_service" is there a better, cleaner way to write this? It seems pretty kludgy to me. I mean it works, but I'd like to clean it up some if I can. – nulltek Jan 15 '14 at 23:10
  • Yea make sure you keep it DRY, extracting that code into a private shared method would make it clean. – supermoogle Jan 15 '14 at 23:13
  • I do plan to DRY it up. This was my first Rails app and I'm in the process of refactoring pretty much everything. I was just wondering if there's a cleaner way to write the in_service action. What I wrote, works but there's definitely a better way. Thanks for the DRY example, that really cleans things up! – nulltek Jan 16 '14 at 00:37