Rails Scaffolding - Automatic Navigation Generation

I’ve been working quite a while on this prototype project now and I’m quite happy to admit that the majority of the work has been an exercise in wrapping up a scaffolded application into something more presentable and usable for the target audience. This post is going to try and describe what I think could work for future applications in the style of a Rails Recipe.

Problem Description

As I’ve gone through the process of making tweaks and alterations to the main scaffolded files to achieve what I’ve wanted, I’ve realised that while hooking together sets of scaffolds can get you so far – presenting the user with an intuitive navigation for accessing these scaffolds could be the main stepping stone in moving from scaffolds to a first demonstrable prototype.

For most applications the user will be aware of some top level CRUD feature (or set of features) which will guide their use through the rest of the application. Even DHH himself is suggesting we embrace the ‘CRUDness’ of our applications, so I think our navigation should be able to automatically represent the model structure and hierarchy of our system.

Essentially what I would like is a helper that can take the current controller or action and, based on our model structure, suggest appropriate related controllers to access and provide a way of navigating the hierarchy of our system. If everything is CRUD-based this should result in natural learning and use of the system, especially if the user is already familiar with the hierarchy of a domain, e.g. the application is to supplement or replace an existing set of processes.

The Solution

My suggestion is that we extend ActiveRecord::Base to provide the extra functionality I would like. If we modify the class by way of a Mixin, we can add functionality to the class and assume that any future derived classes (Models) will share this functionality.

Let’s set up an example to follow – below is a set of models which make up part of a system.

class Spend < ActiveRecord::Base

  belongs_to :currency

  belongs_to :service

end



class Service < ActiveRecord::Base

  has_many :spends

end



class Currency < ActiveRecord::Base

  has_many :spends

end

Quite a simple set of relationships to begin with. As far as foreign records are concerned a Spend record is composed of the Service we are spending on and the Currency of the spend.

Using Ruby Reflection to access associated models

ActiveRecord has a method of querying the class itself to return all associations – this is how the rails code can determine what tables to join etc when performing queries. The ActiveRecord API for reflection tells us that the method reflect_on_all_associations can return an array of AggregateReflection objects. The base class of the AggregrateReflection (MacroReflection) is where we can find the information we want – the class of the associated models.

The code below shows how you can wrap up these method calls into something more friendly. I don’t really want to be handling these kind of objects regularly in my code anyway!

class Spend < ActiveRecord::Base

  belongs_to :currency

  belongs_to :service



  def self.get_associated_model_classes(type = :belongs_to)

    # defined as self.get.. as we want to call the method on the class

    aggregate_objs = self.reflect_on_all_associations(type)

    out = Array.new

    aggregate_objs.each do |mr|

      out << mr.klass

    end

    # all this ‘out’ stuff can be replaced with:

    # aggregate_objs.map {|m| m.klass}

    out

  end

end

I’m sure there is a much cleaner way to handle the array processing and output, probably in the form of aggregate_objs.map {|m| m.klass}, but when I wrote the code I was still struggling with getting my blocks working properly, so I keep track of my returns with a variable called ‘out’ just in case.

So now, if you put all that code into IRB (after requiring active_record.rb and active_support.rb), you should be able to run the following:

irb(main):037:0> Spend.get_associated_model_classes
=> [Currency, Service]
irb(main):038:0>

Air Guitar! Now we have a workable array of classes to play with. Unfortunately this is limited to working with the Spend class, which is pretty useless. Now we’re going to bolt this functionality onto the AR::Base class so that all of our models can be queried in the same way. We will do this with a Mixin.

Extending ActiveRecord with a Mixin

Coming soon…I’ve decided to split this into 2 or 3 parts otherwise It’s going to take me til the end of the week before I get anything online. Release early!

Comments (3)

Always save a draft!

So I was up quite late last night. After learning some cool new stuff about RoR I decided I should document my journey and write a post about it. Spent about 2 hours putting something together in the format of a Rails Recipe and left it to be finished in the morning.

Windows Update decided it wanted to install some new version of .NET for me last night however, so rebooted the machine at 3:07AM, closing all open windows, including the Firefox instance I was editing my post in.

Wordpress needs auto-save draft (ala gmail) asap.

Comments (3)

Where have I been?

Everything came to a stop last week, but this time it’s for a very good reason!

I got my first Rails contract!

There has been much rejoicing and a lot of really enjoyable coding going on since I had the go-ahead for the project, so hopefully this is the start of a trend now that I can put Rails on the Beanlogic skillset officially.

I’d say more about the project, but unfortunately I’m tied up in NDAs for it. All I can say is that I’m developing a prototype for an application for a rather large bank. The best part is that Rails has managed to perform very well with a very large dataset, so the whole thing might not end it’s life as a prototype…I might get the contract to develop it completely into a production app…fingers crossed eh!

YEAH!

Comments

More randomness

Have got a bit closer to what I want to achieve with these randomly generated graphics. I have introduced what I am calling ‘paths’ to yesterday’s random movement code. Basically when the walker is generated it is issued a direction modifier and a count for how many steps that modifier should be applied to it’s current trajectory. This means I can set walkers off on randomly generated curve paths and see what happens.

Next step is to implement some kind of collision detection so that I don’t get bundles of walkers mashing up in the same area as this can create quite a nasty effect. When they do sprout off from the ‘pack’ there’s a good chance the effect will look cool though!

Walkers with paths

Demo here, Source here.

Comments (3)

Back to basics!

Have had a weird couple of days recently. After deciding to merge my blogs, my priority was to get a custom design for this site online ASAP, so about a week ago I was playing in Photoshop and while I could get the colours and the rough layout pretty much how I wanted it, I knew there was detail missing that I really wanted to achieve. Unfortunately I’m not skilled enough (yet) to get the blurry design ‘idea’ out of my head and onto paper *or* digital canvas, so I started thinking in terms of representing the kind of thing I wanted as code…

I remember a long long time ago, in a Flash channel on EFNet (it was either #flashhelp or #actionscript), saying to some of the regulars there that I wanted to get to the point where I could create ‘pretty’ things with code. I started messing around with movieclip-based particle systems and was enjoying where it was going, and then I got a full time job as a web developer and that was pretty much the end of my journey into what is now called Generative Art.

Well now I’ve decided to pick up where I left off, with a short term goal of creating an interesting and unique set of graphics for this site and a long term goal of flexing what little creative muscle I have and hopefully learning and developing my skills on the way.

I’ve uploaded my day-1 efforts – it’s simple stuff as you can see if you check out the source, but it’s a good starting point to build on I think.

Have a look at it here, and download the source here.

If you’re into this sort of thing there are loads of sites out there with some truely excellent work to view. A good starting point is the CodeTree project, where I have just made my first submission!

Update
After a request on IRC, I’ve uploaded 2 other versions:

Larger – Same as first but on a much bigger canvas
Larger, Dark with auto – using colours from my first tests, with mouse-click to activate auto mode

Flash random generator image

A capture from the last version posted – I’m loving the dark spacey feel it creates – I’m going to modify this to generate similar scenes rapidly so I can just see the finished result as I quite like it.

Comments

« Previous entries · Next entries »