stonean

Generator: Stage

Update: Stage has become a gem and project details can be found at stonean.com

This post was updated on 04-27-08 to reflect the improved design. I’m using the RubyOnRails methods as this is where Stage was born, but Stage is available for Merb as well.

I’ve just completed a new generator called stage. This is a direct copy/modification of the scaffold generator included with Rails 2.0.2.

Stage was born out of a desire to remove as much code as possible from the view. I didn’t want to create a new markup, I wanted to use the existing architecture more efficiently.

To use Stage, you first need to grab it:

sudo gem install stage

Then you use stage just like scaffold:

./script/generate stage author first_name:string last_name:stringexists  app/models/exists  app/controllers/exists  app/helpers/create  app/views/authorsexists  app/views/layouts/create  app/views/data/create  app/views/authors/index.html.erbcreate  app/views/authors/show.html.erbcreate  app/views/authors/new.html.erbcreate  app/views/authors/edit.html.erbcreate  app/views/authors/_form.html.erbcreate  app/views/authors/_data.html.erbdependency  modelexists    app/models/exists    test/unit/exists    test/fixtures/create    app/models/author.rbcreate    test/unit/author_test.rbcreate    test/fixtures/authors.ymlcreate    db/migratecreate    db/migrate/001_create_authors.rbcreate  app/controllers/authors_controller.rbcreate  app/helpers/authors_helper.rbroute  map.resources :authors

So, what’s different? With the exception of the index view, the contents have changed quite a bit.

Edit:

<h1>Editing Author</h1>

<%= render :partial => "form" %>

<%= link_to 'Show', @author %> |<%= link_to 'Back', authors_path %>

New:

<h1>New Author</h1>

<%= render :partial => "form" %>

<%= link_to 'Back', authors_path %>

Show:

<%= render :partial => "data" %><%= link_to 'Edit', edit_author_path(@author) %> |<%= link_to 'Back', authors_path %>

And theres a new partial called form. As you can see this is called by edit and new:

<%submit_label = "Update"submit_label = "Create" if @author.new_record?-%>

<%= error_messages_for :author %>

<% form_for(@author) do |f| %>  <%= render :partial => "data" %>  <p> <%= f.submit submit_label %> </p><% end %>

We’ve now removed the duplication in new, edit and show by having them all reference the data partial.

I’ve had this construct for a while, but the data partial always ended up with too much code. If I’m in edit mode, show the input tag, else show the text, etc…, etc…

It could get rather ugly. So, I decided to really start using the helpers. I have used them before when there would have been “too much” code in the view. I guess I’ve changed my definition of “too much”.

Here’s the data partial:

<p>  <b>First name</b><br/>  <%= author_first_name_value %></p><p>  <b>Last name</b><br/>  <%= author_last_name_value %></p>

As you can see I am calling a <model>_<attribute>_value method which will give me back the correct form or show value. This construct is used to avoid naming collisions. I had initially designed it without namespacing the methods with the model name, but quickly discovered that was a bad idea.

The @action_name instance variable determines how I’m to render the information. Luckily both Merb and Rails have this same variable.

These methods are defined in the Helper:

module AuthorsHelper  def author_first_name_value   if @action_name == "show"     h @author.first_name   else     text_field_tag "author[first_name]", @author.first_name   end  end

  def author_last_name_value   if @action_name == "show"     h @author.last_name   else     text_field_tag "author[last_name]", @author.last_name   end  endend

I opted on creating a method for each attribute and a clearly outlined “if” block to make modifications easier.

I hope you find this useful and it fits your idea of view structure.

Btw, thanks to Greg Houston for his source formatting tool. It made this post look a lot better than it would have without it.

Written by stonean

January 31, 2008 at 3:15 pm

Posted in RubyOnRails, Stage

4 Responses

Subscribe to comments with RSS.

  1. cool.

    Donald H.

    February 1, 2008 at 12:06 am

  2. This is similar to what I’m doing in my own projects. The main differences are that I name _data.html.erb _author.html.erb, in such a way that it can be used as a partial in other actions (like Article). Of course, that precludes using your “smart” helpers that will just wind up being a maintenance pain as the data model evolves over time.

    Jamie Macey

    April 27, 2008 at 5:21 pm

  3. It occurs to me that meta-defining the helper methods would go a long way to making it more maintainable, without a significant runtime penalty as one might get with a method_missing hook. Apologies for the crappy formatting, blogger’s a bit draconic about pre/code tags.

    module AuthorsHelper
    %w(first_name last_name).each do |field|
    eval < <-DEF
    def author_#{field}_value
    if @action_name == “show”
    h @author.#{field}
    else
    text_field_tag “author[#{field}]“, @author.#{field}
    end
    end
    DEF
    end
    end

    Jamie Macey

    April 27, 2008 at 5:27 pm

  4. Thanks for the comments Jamie. I don’t think having _data as opposed to _author should prevent any code sharing. You would need to qualify the paths anyway. Am I missing something there?

    Other people have mentioned method_missing and constructs similar to your array usage. It’s cool and eliminates a bunch of repetitive code, but I’m just not a fan of this sort of code architecture. As soon as one of the fields differ (password, size, style, etc..) you have to do more work to make a change than you would with the current construct.

    Basically this construct is there with the assumption that something is going to change. So, I think it’s more maintainable this way…interesting how we have different takes on maintainability.

    However, it’s just not mine anymore now is it? :)

    If others express the same wants I don’t see why I couldn’t add a flag in to the generator to provide different templating formats.

    I know it needs to be smarter than it is now and will be working on that in the near future.

    Thanks again for the comments. They are very much appreciated :)

    Andrew Stone

    April 27, 2008 at 6:33 pm


Comments are closed.