Thursday, August 22, 2013

Making Report Views in Ruby on Rails Pt. 2

Following up, once I have access to my views, I simply need to group and loop over my results and put them in a nice table. So, in my app/views/admin/reports/gme_by_opening_html.erb lets get started:

<h1>GME Department Coverage by Site Openings</h1>
<p><%= @results_count %> records returned.</p>

<% @results.group_by(&:dept_code).each do |dept_code,providers| %>
<table class="table table-striped table-bordered">
<thead>
  <tr>
    <th>Name</th>
    <th>Date</th>
    <th>Shift Hours</th>
    <th>Site</th>
  </tr>
  <tr>
    <td colspan="4"><h4><%= dept_code %></h4></td>
  </tr>
</thead>
<tbody>
  <% providers.group_by(&:full_name).each do |full_name, info| %>
    <tr>
      <td colspan="4"><b><%= full_name %></b></td>
    </tr>
    <% info.each do |r| %>
    <tr>
      <td>&nbsp;</td>
      <td><%= r.date_open.try(:strftime,'%-m/%-d/%Y') %></td>
      <td><%= r.hours %></td>
      <td><%= r.name %></td>
    </tr>
    <% end %>
  <% end %>
</tbody>
</table>
<p>&nbsp;</p>
<% end %>


So, what we have here (building on the previous post) is a list of doctors, from different departments who work at sites on different days for specific shifts. The grouping in this report is by department, then by doctor's name and a list of the sites by date. The key here is to group_by(&:_field_).each and then break out a sub grouping. Not too bad. But, wouldn't it be nice to have a filter to cut the data by date or other result? Like if I wanted a quarterly report?

In app/controllers/admin/reports_controller.rb I'm going to have a default time frame and accept filters. Also I'm going to create a nice label based on the dates (I think I'm supposed to put the label construction in the view, but I like it here where I can see all the filters I'm making- like if I wanted to filter on department instead). This code comes from Stack Overflow.

  def gme_by_opening
    if params[:start_date] && params[:end_date]
      filter_start = params[:start_date]
      filter_end = params[:end_date]
      @results = ReportGmeByOpening.where(
        "date_open <= ? AND date_open >= ?", Date.parse(filter_end), Date.parse(filter_start)
      ).order(
          "dept_code", "full_name", "date_open"
      )#.group_by(&:dept_code,:full_name)
      @results_label = "Records from " + filter_start + " to " + filter_end
    else
      @results = ReportGmeByOpening.where(
        "date_open <= ? AND date_open >= ?", Date.today, 1.month.ago
      ).order(
          "dept_code", "full_name", "date_open"
      )
      @results_label = "Records from " + 1.month.ago.try(:strftime,'%-m/%-d/%Y') + " to " + Date.today.try(:strftime,'%-m/%-d/%Y')
    end
    @results_count = @results.count

    respond_to do |format|
      format.html # gme_by_opening.html.erb
    end
  end


Then in my gme_by_opening.html.erb I change the header to:

<h1>GME Department Coverage by Site Openings</h1>
<div class="row">
<p class="span6"><%= @results_label %>, with <%= @results_count %> records returned.</p>
<div class="span6"><%= form_tag(admin_reports_gme_by_opening_path, {:class => 'form-inline'}) do %>
  <%= text_field_tag :start_date, nil, :class => 'input-small' %> to
  <%= text_field_tag :end_date, nil, :class => 'input-small' %>
  <%= submit_tag "Update Date Range Filter", :class => "btn" %>
<% end %></div>
</div>

Thursday, August 8, 2013

Making Report Views in Ruby on Rails

I am in the middle of launching another Ruby on Rails web application that was left to me to finish. I've spent several months adding features, fixing the data models, cleaning up styles and UI. Pretty much maintenance tasks and support but without the main architect or developer. The remaining major issues left for me was to import 8 years of data and develop some reporting functions. I will probably write about the data export/import experience later. However, creating reports was a fairly complicated effort due to not a lot of explicit help or examples.

When I talk about reporting, I am referring to data models that bring together lots of tables worth of data and then allow the viewer to select, sort and filter on their own. In our shrinking and harried unit it is becoming clear that web apps are not the best place to manage data sets of any significance. Security issues, application responsiveness and development speed are all significant obstacles for us. Only ease of deployment and flexibility of access work in a web app's favor. And for in-house, departmental apps that may not be enough of an advantage.

Regardless, this app needs reports!

So, first I create the Views I need in SQL Server. No problem, I do that all the time, but how do I call them in Rails? Stack Overflow has a start for me. And I create a model to call the View I built.

rails generate model report_gme_by_opening

I throw away the migration that is generated and paste in the example.

class ReportGmeByOpening < ActiveRecord::Base
  # attr_accessible :title, :body
  set_table_name "report_gme_by_opening"
  #set_primary_key "if_not_id"
end


I don't need the primary key (there is none) and I don't think I need any accessible attrs since it is read only.

Wait, I need a reports controller in my admin part of the app if this is going to work.

rails generate controller admin/reports gme_by_opening

This gives me a blank controller and a definition of one report controller.

class Admin::ReportsController < Admin::AdminController
  respond_to :html
 
  def gme_by_opening
    @results = ReportGmeByOpening
    @results_count = @results.count
    respond_to do |format|
      format.html # gme_by_opening.html.erb
    end
  end
end


And then I make a gme_by_opening.html.erb file with some basic info.

<h1>GME Department Coverage by Site Openings</h1>
<p><%= @results_count %> records returned.</p>


And then I need to make a route available.

namespace :admin do
  match '/reports/gme_by_opening', :to => 'reports#gme_by_opening'
end


Finally I can make a link like this.

<%= link_to "GME by Openings", admin_reports_gme_by_opening_path%>

All the pieces work and I can get to my page and have some basic output. But next I need some filtering and grouping to make this useful to my customers.

Thursday, April 4, 2013

Server Migration

So, networking found a massive compromise on our ColdFusion server and we've been spending a couple of weeks building a new one and getting it set up. Unfortunately, through the loss of employees to better opportunities, nearly all our expertise in building and deploying is gone. So, I've had to drop nearly everything and relearn how to set up a CF server. Not my favorite thing to do.

Thursday, March 28, 2013

Rails vs MS SQL Server

So, I am finishing off a couple of Ruby on Rails apps that fell to me (from where I had just a supporting role) to finish and deploy. Several bugs that appeared in the production app where it had worked fine in development gave me fits.

Most had to do with the way that the development SQlite seemed to be more permissive than the production's MS SQL Server. Sometimes, updating rails to 3.2.x would fix it. But that would also introduce new problems.

The worst was when I finally got my bug list squashed only to have new bug for settled issues appear. Suddenly my .empty? statements stopped working. So I switched to .blank? on advice from Ruby Quicktips. I suppose I need to do some deeper reading on the language rather than just Googling when I need a function. Part of the trouble is that I will have to pay attention to Ruby versions and what might or might not work with a database.

I think it is also time to stop doing tutorials and actually write an app up from scratch.