rails: adding a preview option to new form

Suppose we wanted to modify a basic Rails application so there was the option of a preview before creating a new record.

What is a good pattern for adding a second button to a form?

There are two options:

  1. One controller action with a flag: nice articles by EyeDeal and Myers Development (from 2008 and 2006, respectively, but still accurate)
  2. Two controller actions where there are two form buttons that each post to a separate action

I like having two controller actions, since it feels to me like different behavior should live in different actions. The complete code is posted on github, which creates a new_preview action, slightly modifies the new action so it can be called with parameters, and makes corresponding view changes.

Here’s what I did to create the app (on the command line):

rails notes
cd notes
ruby script/generate scaffold note title:string content:text

Then I edited app/controllers/notes_controller.rb:

def new_preview
  @note = Note.new(params[:note])
end

Then I edited app/views/notes/new.html.rb to add a button that triggers the new action (see whole file):

  <%= f.submit 'Preview', :onclick => "this.form.action='new_preview'"%>

And then I created the new_preview template file (app/views/notes/new_preview.html.erb) which I made look just like the show page with a hidden form:

<p>
  <b>Title:</b>
  <%=h @note.title %>
</p>
<p>
  <b>Description:</b>
  <%=h @note.description %>
</p>
<% form_for(@note) do |f| %>
  <%= f.hidden_field :title, :value => @note.title %>
  <%= f.hidden_field :description, :value => @note.description %>
  <p>
    <%= f.submit 'Re-Edit', :onclick => "this.form.action='new'" %>
    <%= f.submit 'Create' %>
  </p>
<% end %>

and finally, I edited the ‘new’ action so that it could accept parameters to fill in the form (to handle the case of “Re-Edit”)

  def new
    @note = Note.new(params[:note])
    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @note }
    end
  end

Overall I like this solution. There is a clear separation of code between preview and create.

However….

There was some interesting discussion via twitter about this. I must admit that using onclick like that feels a little hack-ish. Greg Moeck offered an alternate methodology, which seemed like a lot of code to solve a simple problem. Elad Meidar argued that my technique was obtrusive. I wonder… seems to me that the whole idea behind unobtrusive Javascript is to separate behavior from structure. But we put behavior in ERB files all the time, like “link_to ‘Edit’, edit_note_path(note)” or even “form_for(@note)” … I wonder if the trick would be :onclick => “this.form.action=’#{new_note_path}’”

Interested in other people’s thoughts, suggestions, code snippets…

3 Comments

  1. Gregory Moeck
    Posted April 8, 2010 at 9:27 am | Permalink

    Your point about it being in a partial to begin with is well taken. It wouldn’t really be a DRY issue. However that “hackish” feeling still just doesn’t sit right with me. The unobtrusive solution I offered above would only have to be written once, and it would work for many different places, not just the preview action. It has a bit more code but it just feels better to me, and it may work out to be less if you end up implementing the sameish functionality elsewhere, pointing at a different action.

  2. Posted June 11, 2010 at 9:51 pm | Permalink

    What do you think about splitting in the controller according to params[:commit]?

    params[:commit] tells you the title of the button that was clicked.

    So invoke make-changes if button-title is ‘Re-Edit’ and invoke create if it is ‘Create’. Make those two constants in the controller, and use the constants in the view.

    Stephan

  3. Posted June 19, 2010 at 10:22 am | Permalink

    Hi Stephan,

    I think your approach is similar to the ones I reference I the top of the article (“1. One controller action with a flag”). It seems like a fine approach. My preference is to have two controller actions, since I think it is cleaner for each controller action to do only one thing.

    Best,
    Sarah

One Trackback

  1. [...] This post was mentioned on Twitter by Sarah Allen. Sarah Allen said: rails: adding a preview option to new form http://bit.ly/9qaE3C — thanks @britt @gregmoeck @eladmeidar @MikeG1 @lenary [...]

Post a Comment

Your email is never shared. Required fields are marked *

*
*