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:
- One controller action with a flag: nice articles by EyeDeal and Myers Development (from 2008 and 2006, respectively, but still accurate)
- 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):
[code]
rails notes
cd notes
ruby script/generate scaffold note title:string content:text
[/code]
Then I edited app/controllers/notes_controller.rb:
1 2 3 4 |
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):
1 2 |
<%= 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<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”)
1 2 3 4 5 6 7 8 9 |
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
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.
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
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
[...] 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 [...]