Mongoid: Make sure all changed objects are saved

With Rails’s ActiveRecord and presumably other object-relational mappers, it is easy to use persistent, database-backed objects as if they were just there. Create new objects, navigate along associations, just like that. This picture breaks down however, when it comes time to ensure those in-memory changes are saved back to the database.

In general, in a single unit of work, we only want to read an object once from the database and write changes to that object, if any, back to the database at most once.

The “reading once” part is mostly handled by an identity map. Such a map does not prevent multiple reads of the same object through conditional queries, but it does ensure that each persistent object has a single in-memory representation and it does avoid reading the same object twice when the object is accessed by its id (primary key).

The writing part is harder, because a changed or new object might not be valid by the constraints imposed by the application or the database. In effect, writing/saving must be done explicitly in order to react to the possible error conditions. In a lot of common cases this fits in nicely with the business logic.

Say your application provides the functionality to send a message. It is part of your business logic to check that the user has indeed entered a valid message, one having some text for the body. So when you write code like this

class MessagesController < ApplicationController
  def new
    @message = Message.create(message_params)
    if @message.errors.empty?
      ...
    else
      ...
    end
  end
end

you are really performing a validity check on the message with the side-effect that a valid message is written to the database.

It is a somewhat different case when objects are changed not directly by the user, but as a consequence of another user action. Say we want to mark a message as read when a user has seen it:

class MessagesController < ApplicationController
  def show
    @message = Message.find(params[:id])
    @message.mark_as_read
  end
end

Now we are coming to the heart of the matter: How do we ensure that the state change (unread -> read) of our message is saved? Maybe like this:

class Message
  def mark_as_read
    self.state = 'read'
    save!
  end
end

That looks fine by itself, but what if we want to make another change to the same object, like this

class MessagesController < ApplicationController
  def show
    @message = Message.find(params[:id])
    @message.mark_as_read
    @message.register_last_reader(current_user)
  end
end

and

class Message
  def register_last_reader(user)
    self.last_reader = user
    save!
  end
end

Note that each method by itself ensures that changes are written to the database. As a result, we can compose these methods easily without any further concern that the changes they effect have to be written explicitly to the database.

Unfortunately, there is a drawback. The price we pay is that the same object is written to the database twice because each change is saved individually.

How about not saving the message in mark_as_read and register_last_reader and instead doing it in the controller action?

class MessagesController < ApplicationController
  def show
    @message = Message.find(params[:id])
    @message.mark_as_read
    @message.register_last_reader(current_user)
    @message.save!
  end
end

This works, needs only a single database write -- and results in less compositional, more risky code because now mark_as_read and register_last_reader implicitly shift responsibility to their calling context.

Now to the denouement. I don't have a handy solution that satisfies all constraints, but I do have a code snippet that helps make the second approach less risky.

This version is for Mongoid, but the idea is applicable to other ORMs that use an identity map. And importantly, the identity map must be enabled for this to work.

What It Does and Why

The after_filter logs and raises an exception if the identity map contains any objects that should have been saved. In particular, these are the objects that have changes to their attributes, excluding non-essential technical attributes, and where no failed attempt has been made to save them explicitly. We don't care for objects with errors, because we assume that such an object is explicitly handled. We do care about the forgotten objects, changed but never saved.

Copying tags between music files

Over the years, I’ve ripped CDs in various formats. In the beginning, it was MP3, but I soon switched to OGG. A few years ago I, it made the switch to FLAC. Unfortunately, that leaves me with a large “sediment” of files in lossy formats and I’ve started to rip those again — for the last time, I hope.

The ripping is tedious, but redoing the tags would be far worse. So here’s a script to help avoid the drudgery.

This is how it is used:

$ copytags.rb --help
Usage: copytags [options] from_pattern to_pattern
    -n, --dry-run                    Don't run any commands, just print them
    -t, --tag                        copy tags from matching files (default)
    -T, --no-tag                     do not copy tags from matching files
    -r, --rename                     rename from matching files
    -R, --no-rename                  do not rename from matching files (default)
    -q, --quiet                      Display less information
    -v, --verbose                    Display extra information
    -h, --help                       Show this message

Examples
    # Copy tags from 1.Track.ogg to 1.Track.flac
    copytags '%.1d.*.ogg' '%.1d.*.flac'

    # Copy tags from 01.Track.ogg to 01.Track.flac
    copytags '%.2d.*.ogg' '%.2d.*.flac'
                                                                                                                                                    
    # Assuming 1.Song.ogg, rename 1.Track.flac to 1.Song.flac                                                                                       
    copytags -rT '%.1d.*.ogg' '%.1d.*.flac'                                                                                                         

And this is the script:

Better Rake Bash completion

What’s new?

  1. Rake tasks are cached (thanks to turadb).
  2. If there is no Rakefile in the current directory, ancestor directories are searched in the way Rake itself does.

Installation

Copy the file to /etc/bash_completion.d or possibly /usr/share/bash-completion/completions or to another place where it is loaded when your Bash shell is started.

Ruby as a language for Rails views

Didn’t you always want to write your Rails views as plain Ruby objects? — “What?”, I hear you say. No, I haven’t lost my mind and the idea is quite sensible (or so I hope), once you add the restriction that it is JSON-formatted data that you want to return.

Say you need to set up some hashes or arrays for rendering to JSON. This is best done in Ruby and it is clearly a view concern. So let’s do it in the views. Like this:

  # app/controllers/movies_controller.rb
  def index
    respond_to do |format|
      format.json do
        @movies = Movie.all
        @count = Movie.count
        render :template => 'movies/index.json.rb'
      end
    end
  end

  # app/views/movies/index.json.rb
  {
    :identifier => Movie.primary_key,
    :totalCount => @count,
    # render @movies does not work as it insists on returning a string
    :items => @movies.map { |m| render(m) }
  }

  # app/views/movies/_movie.json.rb
  {
    :id => movie.to_param,
    :title => movie.title,
    :releaseDate => movie.release_date
  }

Getting it

  • github
  • $ sudo gem install mschuerig-ruby_template_handler

Let your Rails app know about it

In the appropriate place in config/environment.rb add

config.gem "mschuerig-ruby_template_handler", :lib => 'ruby_template_handler'

Bash Completion for the gem Command

The gem command is the command line user interface to the RubyGems system for managing Ruby packages.

This command has a few sub-commands itself and a long list of options that differ per sub-command. Remembering and typing them can be tedious, but thankfully, if you are using the bash command shell, it can help with this task. It only has to be told how.

I’ve packaged the how in this file. Copy it to /etc/bash_completion.d and hope that your bash installation picks it up the next time you start a shell.

On Debian/Linux system that’s just how it works. If this does not work on your particular version of Linux or Unix, you’ll have to look up how completions are handled on your system.

Popular Requests

It was late last night. And the night before, I admit it. I also admit that I don’t know much about what Web 2.0 is all about, but there are two things that I do know: rounded corners are involved and, of course tags and tag clouds.

Tagging is work, therefore ipso facto to be avoided, better still: automated.

Let’s say you want to show people which part of your site are popular. How about a tag cloud of the most requested locations? Well, the first thing to do would be to collect which requests are happening at all. Also, you’d need to attach a sensible, displayable title to the raw request. For the sake of this little demonstration, I’m going to assume that in your template — list.rhtml, edit.rhtml, and brethren — you have an instance variable @title. It could be either defined in the template itself or transplanted there from its controller, it doesn’t matter.

Given all this, you could hypothetically write code like this.

class ApplicationController < ActionController::Base
  collect_popular_requests :max_age => 7.days, :max_count => 10000,
    :title => proc { |controller| controller.response.template.instance_variable_get(:@title) }

Therein further assuming that at most the 10000 most recent requests are kept if they are no older than 7 days. Now that we have hypothetically collected the data to base our tag cloud on, we have to display it somehow. Again, let's assume it could be done with a route like this

map.popular '/', :controller => 'most_popular', :action => 'index'

a controller like that

class MostPopularController < ApplicationController
  helper BoilerPlate::PopularRequestsHelper
  collect_popular_requests :\off # Ignore this place

  def index
    @popular_requests = popular_requests_list.most_popular(30)
  end
end

and for good measure a view (index.rhtml)

<ul class="tagcloud">
<% alpha_reqs = @popular_requests.sort_by(&:title) -%>
<% alpha_reqs.each do |req| -%>
  <%= popular_request_tag(req, :wrap => 'li', :min_size => 30, :max_size => 400) %>
<% end -%>
</ul>

and some CSS for good style

.tagcloud {
  text-align: center;
  width: 70%;
}
.tagcloud li {
  display: inline-block;
  display: -moz-inline-box;
  white-space: nowrap;
  vertical-align: middle;
  line-height: 1.2em;
  padding: 0 0.2em;
}

Well, if you've made it this far, you might even consider doing all of this for real. For a good start, I suggest you download this Rails plugin, install it, create a database table with

$ script/generate popular_requests AddPopularRequests
$ rake db:migrate

and start playing.

Self-conscious Decoration

Variations on the Decorator Design Pattern in Ruby have already been discussed in several places. For my special purpose, none of these approaches works.

The common problem with a decorator based on delegation is the lost sense of self. Method calls of the decorated object to itself are not routed through the decorator, therefore remain woefully undecorated.

The Ruby idiom of aliasing and redefining methods, in effect adding around advice, is possible, when the decoration applies to all uses of the “core” class. It is not suitable when you need decorated as well as undecorated variants.

There’s an almost classical: Just derive a subclass from the “core” class and add the decoration in there. Doing this explicitly is tedious, ugly, and multiplies classes semper necessitatem. Luckily, for us and poor, overquoted Father Ockham, Ruby is a highly dynamic language where things are possible that users of other languages can only dream of (longingly or in nightmares, that’s quite a different issue).

So, without further ado, here’s a simple demonstration of the technique.

class Core
  def m1
    puts "Core#m1"
  end

  def m2
    puts "Core#m2"
    m3
  end

  def m3
    puts "Core#m3"
  end

  def m4
    puts "Core#m4"
  end
end

class Decorator
  class << self
    def new(*args)
      decorate(Core).new(*args)
    end

    private
    def decorate(klass)
      decorated_class = Class.new(klass)
      decorated_class.send(:include, Decoration)
      decorated_class
    end
  end

  module Decoration
    def m1
      puts "Decorator#m1"
      super
    end

    def m2
      puts "Decorator#m2"
      super
    end
    def m3
      puts "Decorator#m3"
      super
    end
  end
end

With that under under our collective belt, here’s the case that motivated my attempt at self-conscious delegation. In a Rails application, I have several layers of FormBuilders. At the base, derived from ActionView::Helpers::FormBuilder is a form builder that provides mechanisms. For example for adding labels to input elements and for automatically displaying appropriate widgets for various association types. On top of that, I have two form builders that add layout specifics; one for CSS-based layouts, one for table-based layouts. I still need a further layer for policy: only show users what they are allowed to see and touch. This last policy layer is, of course, independent of layout (and vice versa!), therefore, short of full-fledged AOP, decoration was the way to go.

class DecoFormBuilder

  class << self
    def new(object_name, object, template, options, proc)
      delegate_class = options.delete(:delegate_builder)
      raise ArgumentError, 'No :delegate_builder given to DecoFormBuilder' unless delegate_class
      decorate(delegate_class).new(object_name, object, template, options, proc)
    end

    private

    def decorate(klass)
      decorated = Class.new(klass)
      decorated.send(:include, Decoration)
      decorated
    end
  end

  module Decoration
    def initialize(object_name, object, template, option, proc)
      super
      # Do whatever initialization you need here
    end

    # Put the decorating methods here and don't forget to
    # call super.

  end
end

Eclipse: Printing Editor Templates using XSLT, CSS, and Firefox

I’m using Eclipse with RadRails to edit my Ruby and Rails code (and, yes, I’ve used it for Java, way back when).

Inside Eclipse the various text editors offer so-called templates. These are snippets of common code with placeholders for variable bits. Type in the abbreviation for a template, then type Ctrl-Space and the abbreviation is expanded to the template code. For editing Ruby/Rails templates are available from the RadRails Templates site.

I’ve only recently started to use templates and I’m still early on the learning curve, that is, I haven’t memorized many of the abbreviations. Unfortunately, Eclipse itself only has a list of templates with their expansions in its modal Preferences window. That’s not very helpful when coding. What Eclipse does have is a function to export templates to XML and that’s what I did.

The exported file looks like this

<?xml version="1.0" encoding="UTF-8"?>
<templates>
  <template autoinsert="true" context="ruby" deleted="false" description="tm - all? { |e| .. }" enabled="true" name="all">all? { |${e}| ${cursor} }
  </template>
  <template autoinsert="true" context="ruby" deleted="false" description="tm - alias_method .." enabled="true" name="am">alias_method :${new_name}, :${old_name}
  </template>
  ...
</templates>

The easiest approach I could think of to make this into something printable is this. First, transform it into HTML using an XSL stylesheet, then make the HTML pretty by styling it with an CSS stylesheet. Luckily, most of this can be done inside a web browser such as Firefox that understands XSLT.

Here’s the XSLT

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
  <html>
    <head>
      <xsl:apply-templates mode="head" />
      <link rel="stylesheet" type="text/css" href="templates.css" />
    </head>
    <body>
      <xsl:apply-templates mode="body" />
    </body>
  </html>
</xsl:template>

<xsl:template match="title" mode="head">
  <title>
    <xsl:value-of select="." />
  </title>
</xsl:template>

<xsl:template match="title" mode="body">
  <h1>
    <xsl:value-of select="." />
  </h1>
</xsl:template>

<xsl:template match="templates" mode="body">
  <dl>
    <xsl:apply-templates mode="body" />
  </dl>
</xsl:template>


<xsl:template match="template" mode="body">
  <dt>
    <xsl:value-of select="@name" />
  </dt>
  <dd>
    <xsl:value-of select="." />
  </dd>
</xsl:template>

</xsl:stylesheet>

And the CSS stylesheet

html {
  font-family: sans-serif;
}

dt {
  border-top: 1px solid #aaa;
  padding-top: 0.2em;
  font-weight: bold;
}

dd {
  margin-top: 0.3em;
  margin-bottom: 1em;
  white-space: pre;
  font-family: monospace;
}

Now, these parts need to be connected. For this, it is necessary to slightly edit the original XML template file. For good measure, I throw in a title.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="templates.xsl" ?>
<templates>
  <title>RadRails Ruby Templates</title>
  <template ...>
    ...
  </template>

You may find that the indentation for the template code looks wrong. The reason is that the code contains tabs for indentation. Ruby convention is to indent by 2 spaces for each level, by contrast, Firefox apparently expands tabs to 8 spaces. A small glitch that can be rectified easily

$ sed -i 's/\t/  /g' template.xml