May 07

RESTful applications built with script/generate have a lot of repetitive code. Each generated controller will define default “index” “create” “new” “update” and “destroy” methods that looks similar from controller to controller.

There are at least FOUR plugins that aim to DRY up RESTful controllers each with their own benefits and weaknesses:

  1. make_resourceful - There’s a great Railscast on make_resourceful.
  2. resource_controller Provides a super-class controller that you inherit from. Pretty sweet at handling nested resources…..but don’t confuse it with…
  3. resources_controller — which uses a declarative syntax instead of a superclass. I like seeing “resources_controller_for :foos” in my code.
  4. resource_this — Heavily uses before_filters, if you’d prefer to see things that way.

I am working on a longer, more in-depth comparison of the available frameworks. but I’ve gotta tell you, a “winner” needs to shake out of this list. Having four very strong and useful, but VERY DIFFERENT, ways to DRY up controllers is not beneficial.

Do you remember when there were six ways to Paginate records in a Rails app? Now we use “will\_paginate”, and that’s how it’s done. Everyone knows how to use will_paginate, and it’s terse, well tested, and well supported.

So, which framework do you use? Let me know. I’m interested.

May 06

In my last post, I described an XML over HTTP service written in Java that I have to integrate with. I expressed a minor and general annoyance at the fact that the developers of this service specify that a “DateTime” parameter be specified in “milliseconds since the epoch”.

There is another typical problem with Java services that isn’t always as evident.

When Congress decides to change the Daylight Savings Time switch dates, the JVM typically needs to be patched separately from the OS it is running on. And this never happens.

So, if you are passing a message to a Java service gateway with a parameter like “delivery time” specified in “milliseconds since epoch”, and you think it’s Daylight Savings Time, but the Java service thinks it’s “Standard Time”, then your message will be delivered an hour late.

I usually deal with that case ad-hoc by specifying a variable in a YAML file, like this:

1
tz-fix: true

And then in my code like this:

1
2
3
4
  # Read in my config
  @@c = YAML.load_file(File.join(File.dirname(__FILE__), "myapp.yml"))   
# ...
  millis = millis - (60*60*1000) if @@c["tz-fix"]

If the remote service talks in “seconds since epoch”, I drop the “* 1000″.

Good luck.

May 06

Working in telecom, I have to integrate my Rails and plain Ruby apps with Java or Unix based systems running on remote hosts. Most often these systems are running remotely and are accessed via an XML-over-HTTP interface (no SOAP, no REST, blah…).

I’ve found that one of the most infuriating things that UNIX and Java “roll your own web service” writers do is specify “time” fields as “seconds since the epoch”. WORSE: Many Java service writers specify time fields as “milliseconds since the epoch”.

Come on, now, people? It’s a web service! Do you really think I care about accuracy in milliseconds?

I won’t go into a rant about this. Suffice it to say: I Find This BS To Be Lazy. It works that way so that the server software doesn’t have to do any complicated date parsing or conversions.

Fortunately, Ruby makes it easy to deal with if you know the right methods to use. Here’s how to convert to a UNIX or Java internal-time:

1
2
3
4
5
rubytime = Time.new  # => Tue May 06 11:11:05 -0400 2008
 
# .. Convert from Ruby time to Unix time. 
unixtime = rubytime.to_i            # 1210086665
javatime = rubytime.to_i * 1000  # 1210086665000

What about converting the other way? The example above are converting the “less precise” Ruby time (no milliseconds) into equally or more precise time formats. What do you do when you have a “milliseceonds since epoch” time and you want to use it in Ruby, but preserve the sub-second precision?

1
2
3
4
5
6
7
8
9
# Add just over a half second to the time used above
millis   = 1210086665555  
 
# adding .0 preserves subsecond accuracy
precise = Time.at(millis / 1000.0) 
 
precise.to_i            #  1210086665
precise.to_f            #  1210086665.555
precise.to_f * 1000  # 1210086665555.0

Now. Go convince all those legacy Java and Unix service writers to stop specifying “Epoch Time” in their interfaces! It’s Just Plain Lazy!

May 03

Alright. The Typo 5.x Standard Issue theme (which I really like, so much that I switched from Scribbish) does not account for the styles used by typo:code macros.

After much headache trying to get Typo to include the typocode themes in minimal.css while rendering themes (so that code would render nicely in any theme that I choose to use), I gave up. Really, I’m not sure I want to override typocode styles in every theme anyway, because someone might come up with an even better set of styles.

So instead, I’ve patched themes/standard_issue/stylesheets/application.css to include the typocode styles. As you can see, code is rendering much more bueno now.

Thanks Brent, for beating me up enough to invetigate a better theme.

If you use Standard Issue and want the updated stylesheet, grab it from my site.

Now, I am working on a bug in the ruby formatting that displays line numbers incorrectly, like this:

May 02

Code Highlighting in Typo is awful, cumbersome, and a pain. I am currently running this blog on Typo 5.0.3, and when I write an article using typo:code snippets using LivePreview, here is what I see:

But then it RENDERS like this, no matter which theme I am using:

GAH! That’s not what I thought I was getting! No friggin bueno! So I decided to try a third party code highlighter.

I really liked the TextMate Syntax Highlighter, but: it didn’t work either.

My friend and former colleague Brendan pointed me to a javascript-based code highlighter that does the formatting on the browser. That makes good sense to me. I like it. But it didn’t work either.

So, I’ve decided to roll up my sleeves and figure out why none of the included themes in Typo will render the code blocks the way I want. 2 hours later, I hate the CSS mess, so I’m spending my evening ripping the whole set of stylesheets apart to make them work right.

Stay tuned.

Apr 30

AttachmentFu is a great plugin. It’s heavily used all over the place to upload images to a Rails app. It’s also good with other file types.

I had a requirement to provide users with the ability to set up an entity (call it a Batch), then upload a number of CSV files to that batch. I used AttachmentFu, FasterCSV, and some Multi-Model editing forms to make the trickery work.

Before starting, I set up the AttachmentFu plugin. If you have never done this before, Mike Clark’s Tutorial is a good place to start. Install the plugin and take note of how you have to set up your Attachment model.

Then, I had to set up a Multi-model editing form. If you haven’t done this before, then you should read Ryan Bates’ tutorial on setting up multiple models in one view. In this situation, I had to modify some of the steps because we’re dealing with File Attachments, not Task objects. Here is what I did:

First I created my “Batch” object.

1
script/generate migration Batch user_id:integer name:string

Then I created my “Attachment” object.

1
script/generate migration Attachment

I use Oracle. In order to make AttachmentFu work, I renamed “size” to “filesize”

1
2
3
4
5
6
7
... In 002_create_attachment.rb
def self.up
  create_table :attachments do |t|
  t.integer    :parent_id # foreign key to :batches
  t.string     :content_type, :filename, :thumbnail
  t.integer    :filesize, :width, :height
end

Then, in my Batch model, I added the Multi-Model handling code. My method differs from the Rails Recipe because you cannot update an attachment once you upload it, only delete it. In the Update action, for each attachment on the model, we check to see where there is an attribute containing the ID of the attachment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# If there is not an ID in an attribute, we delete the attachment.
# ... In batch.rb
has_many   :attachments, :foreign_key => "parent_id", :dependent => :destroy
validates_associated    :attachments
 
def new_attachment_attributes=(attrs)
  attrs.each { |attr| attachments.build(attr) }
end
 
def existing_attachment_attributes=(attrs)
  attachments.reject(&:new_record?).each do |attach|
    attachments.delete(attach) unless attrs[attach.id.to_s]
  end
end
 
def save_attachments
  attachments.each { |attach| attach.save(false) }
end

Then I set up the Attachment model to handle the AttachmentFu-ery.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Attachment < ActiveRecord::Base
  belongs_to     :batch
  has_attachment :storage =&gt; :file_system     # Or S3, or DB, or whatever
  validates_as_attachment
 
  ## Patch to make this AttachmentFu Model object work with Oracle.
  def size
    self.filesize
  end
 
  def size=(bytes)
    self.filesize = bytes
  end
end

Now I needed to build the view and controller support. To keep the app mostly RESTful, we let the standard “Attachment” controller be built by the scaffolding system. Since we will be primarily working with Attachments in the “Batch” view, though, I’ve omitted those details.

Here is the additional controller code in batch_controller.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# GET /batches/new
def new
  @batch = Batch.new
  @batch.attachments.build
end
 
def update
  params[:batch][:existing_attachment_attributes] ||= {}
 
  @batch = Batch.find(params[:id])
 
  respond_to do |format|
    if @batch.update_attributes(params[:batch])
       flash[:notice] = 'Your Batch was updated successfully.'
       format.html { redirect_to batch_url(@batch) }
       format.xml  { head :ok }
    else
       format.html { render :action =&gt; "edit" }
       format.xml  { render :xml =&gt; @batch.errors.to_xml }
    end
  end
end

What’s left? Setting up the views. We leave the scaffolded “index” action for the Batch view in place. Attachments aren’t relevant in that view. But in the “Edit” and “New” views, we need to create a custom form that can handle attaching files in addition to setting up the Batch model object.

Step 1, make the Edit and New actions point to a shared form:

1
2
3
4
<!-- Contents of views/batches/new.html.erb
and views/batches/edit.html.erb
-->
<div class="greybox"><%= render :partial => 'form' %></div>

Then, we set up the shared form in a partial like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<h1>Schedule A Batch</h1>
<!-- views/batches/_form.html.erb: error display code omitted -->
  <% form_for(@batch, :html => { :multipart => true }) do f %>
  <strong>Name:</strong> <%= f.text_field :name %>
  <div id="attachments"><%= render :partial => "attachment", :collection =>  
  @batch.attachments%></div>
  <%= add_attachment_link "Add a File" %>
  Total Line Count: <%= @batch.prod_line_count %>
 
  <input name="batch[user_id]" type="hidden" value="<%= @user.id %>" />
 
  <%= submit_tag "Save Changes" %&gt or &lt%= link_to 'Cancel', batches_path %>
 
  <% end %>

The code above renders the primary Model object, and then renders the associated attachments using the “_attachment” partial. Let’s take a look at that code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="attachments" class="attachment"><% new_or_existing = attachment.new_record? ? 'new' : 'existing' %>
  <% prefix = "batch[#{new_or_existing}_attachment_attributes][]" %>
  <% fields_for prefix, attachment do af -%>
 
  <strong>Attached File:</strong>
  <% if attachment.new_record? %>
 
 
  <%= af.file_field :uploaded_data %>
  <% else %>
  <%= af.hidden_field :id %>
  <%= attachment.filename %>
  <%= link_to_function "remove", "$(this).up('.attachment').remove()" unless params[:action] == "show"%>
  <% end %>
 
  <% end -%>
</div>

This sets the front end up to show the attached files, and provide a link to delete each on on the front end using javascript (unless we are being rendered in the “show” action. We’ll refactor that piece of bad juju later).

The last piece of work to do is to set up the “show” action to display the child records. This isn’t hard. There is no need to modify the default scaffolded view. Just add the partial to show the attachments:

1
2
<-- Add to views/batches/show.html.erb -->
<div id="attachments"><%= render :partial => "attachment", :collection => @batch.attachments%></div>

That’s it. You still have an application that responds RESTfully to Batch and Attachment requests, but when you are a person in front of a browser, you can attach multiple files to your Batch object.