me@jbrains.ca

Permanent link to this article Patching RedCloth: unique footnote hyperlinks

Recently, I integrated Textile into this blog via RedCloth. As I started to write articles in my Adventures in RSpec series, I found I wanted to use footnotes. Since Textile supports them, I figured I was in luck; however, I soon found a hyperlink collision when two fragments of Textile markup appear on the same page, each with the same-numbered footnote. RedCloth simply generates a hyperlink to target fn1 for footnote #1, so if there are two footnote #1s on the same page, they both link to target fn1, making it the equivalent of a race condition.

I looked for guidance to the Textpattern folks. A certain Mary told me that Textile has fixed this problem, but likely RedCloth has not. After some investigation, I agreed that this was the case. I looked through the Textile source, to the extent I can understand PHP, and saw their fix was simple: keep a table of footnote numbers to unique IDs, then use the unique ID in place of the number in the hyperlink and target. I figured that I could do that.

It took a couple of hours, and I’ll spare you the details. Here is what I wrote:

require 'digest/sha1'

class UniqueFootnoteIdGeneratingRedCloth < RedCloth
  def initialize(markup)
    @footnote_ids_by_number = {}
    super(markup)
  end

  def next_footnote_id
    # SHA1 isn't significant; I just figured it'd make a good unique ID
    Digest::SHA1.hexdigest(rand(2**64).to_s)
  end

  def to_html(*rules)
    self.scan( /\b\[([0-9]+?)\](\s)?/ ) do |match|
      @footnote_ids_by_number[$1] = next_footnote_id
    end

    super
  end

  private

  def footnote_ref(text)
    text.gsub!( /\b\[([0-9]+?)\](\s)?/ ) do |match|
      "<sup><a href=\"#fn#{@footnote_ids_by_number[$1]}\">#{$1}</a></sup>#{$2}" 
    end
  end

  def textile_fn_( tag, num, atts, cite, content )
    atts << " id=\"fn#{ @footnote_ids_by_number[num] }\"" 
    content = "<sup>#{ num }</sup> #{ content }" 
    atts = shelve( atts ) if atts
    "\t<p#{ atts }>#{ content }</p>" 
  end
end

I ended up copy/pasting more code than I wanted to, so I’ll have to submit something to why for his perusal. Perhaps this will make it into a future version of RedCloth.

Digg! Discuss

August 26, 2007 04:20 rails, ruby, design, adventures in RSpec

Permanent link to this article Live Preview with RSpec on Rails

Today I’m waiting at Così Cafe for our train to Washington DC for Agile 2007, so it’s time to add the next part of the “preview” feature. I have an internet connection, so I can afford to be a little more aggressive with the story I tackle next, because Google knows all. I think I’ll try to build the real-time preview I imagined earlier this morning. Now I don’t think I can spec-drive the real-time aspect of the preview, but I can certainly spec-drive showing the preview in a nearby window while I’m typing in the posting content text area. To get a sense for how that would look, I do some quick UI design.

In order to make room, I shrink the “content” text area and put the live preview, as it’s called, below it. This looks reasonable to me. In the process, I make one design decision: the <div> that contains the live preview text has the ID content-live-preview, which I’ll need to spec-drive the RJS I’ll have to write.

Speaking of spec-driving RJS, I have no idea how to do that, so I need to read a little about that before I get started.

Unfortunately, after reading Rails Recipes, I’m convinced that I need to implement this first before I can learn how to spec-drive it for next time. I find this happens a lot with Rails: it’s almost too simple. I paste an implementation into my view and inspect it manually. When I do that, it becomes clear that I need an action to handle the live preview, so although I didn’t drive the controller behavior with an automated test or spec, I’m certain I need something. Now I think I can spec-drive the controller behavior. Since this is familiar territory, this should go smoothly. Let’s see.

According to Rails Recipes, all I need to do in my action is render the default template without a layout, which means I will need to move the live preview markup to a new live_preview.rhtml template. I’ll do that first, to make sure it will be wired together properly.

After a few false starts, I have these specs:

describe "Live Preview for weblog postings" do
  it "should have a section to display the live preview" do
    assigns[:posting] = Posting.new(:content => "Some @textile@ content.")
    render "/postings/live_preview" 

    response.should have_tag("div#content-live-preview")
  end

  it "should be able to handle nil content" do
    assigns[:posting] = Posting.new(:content => nil)
    render "/postings/live_preview" 

    response.should have_tag("div#content-live-preview")
  end
end

This is the live_preview.rhtml template:

<div id="content-live-preview" class="entry">
    <%= textilize(@posting.content) if @posting.content %>
</div>

That decidedly doesn’t work. When I consult Rails Recipes, I realize I should display the request parameter posting[content] and not the Ruby object @posting.content. For this, I need to learn how to stub the request parameters in the view. Evidently this is as simple as assigning to a params Hash. I fix the specs to match this new information.

describe "Live Preview for weblog postings" do
  it "should have a section to display the live preview" do
    params[:posting] = { :content => "Some @textile@ content." }
    render "/postings/live_preview" 

    response.should have_tag("div#content-live-preview")
  end

  it "should be able to handle nil content" do
    params[:posting] = { :content => nil }
    render "/postings/live_preview" 

    response.should have_tag("div#content-live-preview")
  end
end

I’m on a green bar, but the UI doesn’t work. Firebug tells me that my controller live_preview method works, but the corresponding <div> is not updating. I don’t know how to spec-drive this, so I need to hack for a while. It’s 14.44; let’s see how long I need to hack.

Fortunately, only about five minutes. I had one <div> too many.

After fixing that, and making a few small changes, it looks like I’m done. I would have preferred to spec-drive the observe_field code, but at least I have less untested code than I used to. Now I can remove the preview button and the code that went with it. It served its purpose; now it can go to its rest.

Digg! Discuss

August 12, 2007 19:52 rails, testing, agile, coding standards, refactoring, design, article, extreme programming, adventures in RSpec

Permanent link to this article Getting Started with RSpec

I decided, at last, to investigate RSpec in the course of my work in Rails. I should be clear about something: I’m not writing Rails code for profit, only for fun and the experience, so I’m learning slowly and not really pushing the envelope the way I would on the job. Read this series with that in mind.

Here is the story I want to implement next: “Preview postings”. That story is for this very weblog. When I add an entry, I want to be able to preview it without publishing it. Of course, now that I write that, I realize that I might also want to preview edits to existing entries, but that’s another story. I suppose this story is “Preview new postings”. It’s good to know that I can still negotiate scope with myself!

Not being a big RSpec user yet, rather than get stuck writing a story test, I thought I’d do my bit of design, dive in, then RSpec-drive my model1.

First, I had to install RSpec and RSpec on Rails. That wasn’t too hard. I followed these instructions and issued these commands in the root of my Rails project:

ruby script/plugin install -x svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec
ruby script/plugin install -x svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails
ruby script/generate rspec

After a few seconds, I could run my specs using the new Rake tasks in my project, like spec. When I run my specs, of course I have none, but I do see weird ANSI codes in my output. I’ve asked a question about that, and when I get an answer, I’ll let you know what I found out.

It’s time to write a spec. My design has a class Posting, so I figured I would add the notion of “publishing” a posting, so that I could save a posting without publishing it. This would allow me to preview it. For this, I decided to add a published_at timestamp. For that, I wrote this spec:

describe Posting do
  it "should not yet be published" do
    Posting.new.should_not be_published
  end
end    

What I find neat and disturbing at the same time is that RSpec magically looks for a method published? on Posting because I’ve used the “should… be” syntax. I think it’s neat, but what disturbs me is that I have to know where the underscores go. I expect to write that as Posting.new.should not_be_published or Posting.new.should_not_be published. Not exactly “least surprise” for me2.

I satisfy this spec by adding a published? method than answers false and move to the next spec.

describe WeblogController do
  it "should be published when it has a published timestamp" do
    new_posting = Posting.new(:published_at => DateTime.now)
    new_posting.should be_published
  end
end

To satisfy this spec, I add the column published_at to the postings table. When I migrate, though, I should mark all the current postings as published, so I make them published as of the time they were created. It’s not perfectly accurate, but it will do. I haven’t been tracking the last updated at timestamp. Here is the migration I wrote:

class EnablePreviewForPostings < ActiveRecord::Migration
  def self.up
    add_column :postings, :published_at, :datetime, :default => nil

    Posting.find(:all).each { | each |
      each.update_attribute(:published_at, each.created_at)
    }
  end

  def self.down
    remove_column :postings, :published_at
  end
end

When I migrate the database, I see that all is well. Now I can implement published? like so:

class Posting < ActiveRecord::Base
  def published?
    !self.published_at.nil?
  end
end

I’m green, so I can continue3. The essence of preview is that I can save the entry, display it, but not include it in the published entries. To that end, I need to retrospec the method that grabs all the postings so it’ll exclude unpublished ones. This is the first time I’m spec-ing a controller, so I’ll learn something. I create my new spec at $RAILS_ROOT/spec/controllers/posting_controller_spec.rb and write this:

describe WeblogController do
  fixtures :postings

  it "should only select published entries when browsing" do
    get 'browse'

    postings = assigns[:postings]
    postings.size.should == 3   # 4 articles, 3 published
  end
end

Unfortunately, this doesn’t find my existing postings fixture. I get this rude answer:

No such file or directory - /Users/jbrains/Workspaces/dauphin/jbrains.info/spec/fixtures/postings

(I should note that that’s not the exact output, but the exact output tripped some security filter at TextDrive, so I couldn’t paste it in. That only cost me a half hour to figure out. Thanks, TextDrive.)

So what does Google have to say about this? Curiously, one article says Lose the fixtures with rSpec, which I like, so I’m inclined to try it. I change my spec to this:

describe WeblogController do
  it "should only select published entries when browsing" do
    Posting.create!(
      :published_at => nil,
      :title => "Irrelevant detail", :content => "Irrelevant detail" 
    )

    get 'browse'

    postings = assigns[:postings]
    Posting.find(:all).size.should == 1
    postings.size.should == 0
  end
end

I don’t like the irrelevant details, but when I try to switch to test doubles, it’s a dead end, so I stick with this spec and try to satisfy it. By adding the condition published_at is not null, I get the job done. The problem, though, is that there are two code paths in my browse method, depending on whether the URI is /browse or /browse/12. The latter means “show only articles in category 12”, which supports my entry tags. I wrote this before I knew about custom routes, so I could consider refactoring to a custom route and simplifying browse, but that’s more work than I’m willing to take on at 01.25, so I’ll leave a REFACTOR comment and add a spec for the /browse/12 case.

describe WeblogController do
  it "should only select published entries when browsing within a single category" do
    category = Category.create!(:name => "Irrelevant detail")
    Posting.create!(
      :published_at => nil,
      :title => "Irrelevant detail", :content => "Irrelevant detail" 
    ).categories << category

    get 'browse', :id => category.id

    postings = assigns[:postings]
    Posting.find(:all).size.should == 1
    postings.size.should == 0
  end
end

That spec is violated, so I satisfy it. After some refactoring, browse looks like this:

class WeblogController < ApplicationController
  def browse
    if params[:id].nil?
      @postings_pages, @postings = paginate :postings, :order_by => default_order, :conditions => [published_condition], :per_page => 5
    else
      # REFACTOR Move this to a custom route
      @postings_pages, @postings = paginate_collection(:per_page => 5, :page => params[:page]) {
        Posting.find_by_sql([
          %Q(
            select * from postings where postings.id =
            any (select posting_id from tags where category_id = ?)
            and (#{published_condition})
            order by #{default_order}
          ), params[:id]
        ])
      }
    end
  end

  private

  def published_condition
    "published_at is not null" 
  end
end    

I’m pretty happy with that, and I can’t think of another spec that might be violated, so I move on to the “preview” action. I imagine this is as simple as adding a “preview” button to the form where I add a posting which creates the entry without publishing it, then display it a new window. This way I can close the window, go back, then press “save” when I’m ready. I might even rename “save” to “publish” to emphasize the fact that I’d be publishing the entry. I need to do some more retrospec-ing (“retrospecking”?) to prepare for that.

describe PostingsController do
  it "should not publish a new entry when I preview it" do
    post 'preview'

    new_posting = assigns[:posting]
    new_posting.should_not be_published
  end
end    

I can satisfy that easily enough.

def preview
  @posting = Posting.new(params[:posting])
  @posting.save
  redirect_to :action => "read", :id => @posting
end

Rather than pop up a window, I’ll just remember to use the “Back” button. My customer side wants a real-time preview, and it’s now 01.54, so since I’m not prepared to do that now, my programmer side will ship the simplest thing that could work, get feedback, then add the cool Web 2.0 crap. The next step is to add my preview button, but the scaffold code doesn’t directly handle two submits for the same form, so I need to do some research. The best solution I find is to add a name attribute to my buttons and “case” on the name in my controller method. Not pretty, but adequate. I refactored my new entry form to prepare for that, and when I did, I noticed I couldn’t see any new entries. Of course, that’s because create doesn’t publish. I was hoping to do that later, but I guess I need to do it now. Since I’m on a green bar, I can retrospec create.

describe PostingsController do
  it "should publish a new entry when I publish it" do
    post 'publish'

    new_posting = assigns[:posting]
    new_posting.should be_published
  end
end

Evidently my subconscious insists I rename create to publish, so I do that. Now my spec is violated, so I satisfy it. In the process, I introduce the new method publish on Posting, which I’ve spec-driven.

class Posting < ActiveRecord::Base
  def publish
    self.published_at = DateTime.now
    save
  end
end

This makes the change to the controller easier.

def publish
  @posting = Posting.new(params[:posting])
  if @posting.publish
    update_tags_for(@posting)
    flash[:notice] = 'Posting was successfully created.'
    redirect_to :controller => 'weblog'
  else
    render :action => 'new'
  end
end

I only had to change @posting.save to @posting.publish. That looks like that works, so I try it manually through the UI4. Now I can publish a new entry, so I need to be able to preview one. It’s time for another spec.

describe PostingsController do
  it "should preview when I press the 'Preview' button" do
    post 'submit_new', :submit => "preview" 
    assigns[:posting].should_not be_published
  end
end

Satisfying this spec is pretty straightforward, so I retrospec for the ‘Publish’ case. After a little refactoring, I have this:

class PostingsController < ApplicationController
  def submit_new
    self.send(params[:submit].downcase)
  end
end

Clever, no? Perhaps too clever, but time will tell. It works for me. I’d worry about a security hole if I weren’t the only user who could submit this form.

A quick manual test reveals a problem: “Couldn’t find Posting without an ID.” It looks like I’m missing a preview-related spec, so I add one… and when I do, all hell breaks loose. Here’s the short version of the story:

  1. I noticed my authorize filter wasn’t right, so I fixed it.
  2. I didn’t notice that this would cause all my specs to fail because they don’t login with an authorized user first.
  3. I didn’t notice that this was the problem, because I made a change to unspec-ed code and didn’t think anything of it.

Great how that happens, no? So I search for something on the topic of how to stub out filters, and I read this, which suggested I write

controller.stub!(:login_required).and_return(false)

to indicate that there’s no need to login. I tried that and it didn’t work, so I added this instead:

describe PostingsController do
  before(:each) do
    controller.stub!(:authorize)
  end
end    

Now everyone is authorized in my specs. With that distraction out of the way, I can get back to the point.

describe PostingsController do
  it "shouldn't preview an incomplete entry" do
    post 'preview', :title => "", :content => "" 
    assigns[:posting].should be_new_record
    assert_redirected_to :action => "new" 
  end
end

This is violated because I redirect to the wrong place. It’s an easy fix, but with a little manual testing, I see that while “Publish” gives me nice error messages when it fails, “Preview” doesn’t. Upon further inspection, it’s because preview redirects to new on failure, rather than merely rendering it, as publish does. I should write a spec for that. This time, I add some expectations to the last spec I wrote.

describe PostingsController do
  it "shouldn't preview an incomplete entry" do
    post 'preview', :title => "", :content => "" 
    assigns[:posting].should be_new_record
    response.should_not be_redirect
    response.should render_template("new")
  end
end

I notice that I had typed assert_redirected_to up there. Old habits die hard, especially when the fingers can work without the conscious mind. Frightening. This spec is violated because I redirect, so I fix that. Now I see that publish and preview are structurally similar.

def publish
  @posting = Posting.new(params[:posting])
  if @posting.publish
    update_tags_for(@posting)
    flash[:notice] = 'Posting was successfully created.'
    redirect_to :controller => 'weblog'
  else
    render :action => 'new'
  end
end

def preview
  @posting = Posting.new(params[:posting])
  if @posting.save
    redirect_to :action => "read", :id => @posting.id
  else
    render :action => "new" 
  end
end

The differences? The method they invoke on @posting and the true branch of the if statement. It takes a little to refactor this, but I arrive at the following.

class PostingsController < ApplicationController
  def publish
    save_posting :publish, :on_success => lambda { | posting |
      update_tags_for(posting)
      flash[:notice] = 'Posting was successfully created.'
      redirect_to :controller => 'weblog'
    }
  end

  def preview
    save_posting :preview, :on_success => lambda { | posting |
      redirect_to :action => "read", :id => posting.id
    }
  end

  private

  def save_posting(save_action_symbol, events)
    @posting = Posting.new(params[:posting])
    if @posting.send(save_action_symbol)
      events[:on_success].call(@posting)
    else
      render :action => 'new'
    end
  end
end

Now, I think, the feature works. Just to be sure, I try a few manual tests. I would prefer to rely on specs, but it’s 03.21 and I don’t plan on much more retrospec-ing tonight. One thing I notice is the “preview” view doesn’t say anything about being a preview, so I should fix that.

describe PostingsController do
  it "should tell me a preview is a preview" do
    post 'preview', :posting => {
      :title => "Irrelevant detail",
      :content => "Irrelevant detail" 
    }

    response.should redirect_to(
      :action => "preview",
      :id => assigns[:posting].id
    )
  end
end

Making that pass is easy: I redirect to preview, rather than read. A little manual inspection reveals that nothing about the “preview” template makes it look like a preview, so I add a little color to make that more obvious. I’ll go with this for now:

<% @title = "Preview '#{@posting.title}'" %>
<div style="border: 1px solid; padding: 5px; background: pink">
<%= render :partial => "posting" %>
<p style="text-align: right">preview</p>
</div>

It looks reasonably good, and although I have to use the browser’s Back button to edit the draft, and although the “edit” button in the entry doesn’t do what I expect, I can live with it for now.

So, my first RSpec experience has been a good one. In spite of a couple of minor problems, I felt I proceeded steadily, if a little slowly. I imagine I could get used to this quite quickly. RSpec on Rails is a terrific plug-in.

Still, I’d prefer not to have to create real entries in order to write specs for my controllers. I’m sure there’s a better way, but learning what that is will have to wait for another day. It’s 03.43, I have to pack and get some sleep before traveling from Philadelphia to DC for Agile 2007. Before I go, though, I should deploy.

In the process of preparing to commit my changes to my code repository, I updated the RSpec plug-ins, and can no longer run my specs. It looks like a problem in one of the plug-ins. Needless to say I’m not impressed with that. Fortunately, it’s not a big problem: I simply needed to do script/generate rspec again, and all was well. As a result, I’d better freeze my plug-ins before deploying. How do I do that?

Ask, and ye shall receive.

So while that took longer than it usually does, I was able to preview this entry with the new feature, so I’m satisfied with it. The next step might be to add real-time preview or the primitive preview feature when editing an entry. Either way, I learned a lot, and I think I’ll be more comfortable spec-ing my next new feature.

1 What’s the verb for doing BDD? In TDD, we say “test-drive”. What do I say when doing BDD with RSpec? Write me and let me know.

2 I tried Posting.new.should_not_be published, but it didn’t work. Shame.

3 You can change some of the language of TDD, but you’ll take my green bar from my cold… well, you get the idea.

4 Yes; I wrote untested, unspec-ed code. I’m not proud of it. Why do you think I’m writing this article?

Digg! Discuss

August 12, 2007 08:29 rails, ruby, testing, agile, refactoring, design, article, extreme programming, adventures in RSpec

Permanent link to this article From Java to Ruby

About a year ago I wrote that I was no longer a Java programmer—or rather, that my days as a professional Java programmer were numbered. I wrote this in reaction to the announcement that sooner or later the Java language was going to force us to use parameterized types. I simply found that too depressing to continue, so I chose that as a good time to switch to Ruby and have already implemented one small, but successful piece of software on the Rails platform: this weblog. Fortunately, I don’t have a manager dictating the technology I use for my projects. On the contrary, we have just started a medium-sized project in Rails, rather than being beholden to a client’s “requirement” to use a legacy platform like Java Enterprise Edition or .NET. It’s quite liberating.

Still, if I did have to convince a manager, director or client to choose Rails over Java EE, I’m glad I now have Bruce Tate’s From Java to Ruby to give them. It is a quick read, as most of the Pragmatic Programmers’ books are, and it does a very good job of outlining the advantages and disadvantages of Ruby as a development platform. If you know Ruby, then you won’t be surprised by his arguments in favor: shorter development cycles, higher productivity for simpler tasks, more design flexibility and quicker feedback. If you’re a Ruby fan then you might be surprised to read about the disadvantages, because they are likely things that do bother your manager, but don’t bother you. I’ll invite you to read the book, rather than enumerate them here.

If you are thinking of starting a grassroots movement in your organization to move even one subproject from Java to Ruby, then you need to read this book, understand its message, then be better capable of formulating an argument your management can appreciate, understand and believe. If you don’t, then you might be dooming yourself to yet another “crackpot disinformation campaign”, the kind of thing I used to do at IBM before I knew any better.

If you are a manager and your people have started putting pressure on you to adopt Ruby as a development platform, this book will help you navigate the waters, learn how to dip your toe in, or give you the solid arguments you need to convince them that you’re not ready. I suppose you could just veto them with an “I told you so”, but a reasoned argument will be better received and less likely to drive them a step closer to polishing up their resumes.

Bruce Tate’s From Java to Ruby is an indispensable field guide to those who need to decide whether to carry out a campaign to supplant Java with Ruby as your development platform of choice.

Digg! Discuss

October 22, 2006 05:32 rails, java, ruby, people, review

Permanent link to this article Rails: associations, foreign keys and NOT NULL

I’m confused, and I welcome some help.

The Rails application I am working on has a richer model than my weblog does, so I have had to work with associations between model objects more than I had to before. This, on its own, is not a problem. The problem occurs when I combine Rails associations with NOT NULL foreign keys. It seems to be slowing me down.

Here’s an example: when you register for XP Day Montreal 2006, you can request an invoice if your company is forward-thinking enough to pay your way. (I’m just jabbing a little—hold your cards and letters.) No problem: you enter your company’s contact information and we e-mail them an invoice. So far, so good, but what happens when we consider what happens in the model… and the database?

It’s no surprise that an Order has_one :invoice and that an Invoice belongs_to :order, I hope. This means that table invoices has a foreign key to orders, referring to the latter’s id column. Of course, an invoice shouldn’t exist without an order to which to attach itself, so the foreign key is NOT NULL. I would think this makes perfect sense, but I’m finding it difficult to deal with in Rails. The problem comes when I try to attach the invoice to its order in my controller. I seem to have fallen into a chicken-and-egg problem.

When someone requests an invoice, it’s possible they don’t type enough information in, so of course I have added validate_presence_of for those attributes of Invoice. Now the only way I know how to check whether the invoice is fully filled-in is to save it:

  def request_invoice
    flash[:notice] = "We have sent an invoice as requested." 
    @invoice = Invoice.new(params[:invoice])
    if @invoice.save
      session[:order].invoice = @invoice
      RegistrationMailer.deliver_invoice(@invoice)
      redirect_to :action => 'thank_you'
    else
      render :partial => 'request_invoice'
    end
  end

The problem is that when I try to invoke Invoice#save, I get this:

ActiveRecord::StatementInvalid: RuntimeError: ERROR     C23502  Mnull value in column "order_id" violates not-null constraint....

Now, since I invoke Invoice#save explicitly, and before the invoice is attached to the order, the invoice’s order is nil. Just before I attach the invoice to its order, the database complains that I’m inserting a NULL into a NOT NULL column. I wouldn’t have this problem if I didn’t invoke Invoice#save, but then I wouldn’t validate the invoice’s fields that way, either.

Damned if I do…

From where I sit, here are my options:

  1. Remove the NOT NULL constraint from the order_id column, which I dislike, because a NULL foreign key doesn’t make sense here.
  2. Explicitly set the :order attribute on the new invoice, which I dislike, because everything I’ve read makes it look like I shouldn’t have to do that.
  3. Validate the invoice another way, such as invoking Invoice#validate directly. I’m unsure of this, because I don’t even know whether it’ll work at all, and I’ve never had to do explicit validation before, so it seems too low-level—Rails ought to handle this for me, somehow.

So since I don’t know what good Rails style is yet, I could use some advice.


I decided to invoke Invoice#valid? instead of Invoice#save, since that communicates best of the above options. If there’s something obviously better that I should I have done, do tell me.

Digg! Discuss

July 08, 2006 03:01 rails, ruby

Older entries | Older entries at diasparsoftware.com