thinksimple.pl

How to make an entry preview

April 11, 2009

UPDATE: there is now a plugin doing exactly what is described here. Read all about with_preview plugin!

If you have a blog you sometimes need to see what your entry will look like before you post it. Although the thing might seem complicated, this is quite easy to achieve.

First, let’s have a form for our blog post:

<% form_for :entry, :html => {:id => :entry_form} do |f| %>
  <%= f.text_field :title %>
  <%= f.text_field :tag_names %>
  <%= f.text_area :content %>
  <%= f.submit 'Create' %>
<% end %>

We will split that form into divs:

<% form_for :entry, :html => {:id => :entry_form} do |f| %>
<div id="entry_edit">
  <%= f.text_field :title %>
  <%= f.text_field :tag_names %>
  <%= f.text_area :content %>
</div>
<div id="entry_preview">
</div>
  <%= f.submit 'Create' %>
<% end %>

Now let’s add a button which will send an AJAX request to server with our form data:

<%= button_to_remote :Preview, {
  :update => :entry_preview, 
  :url => preview_entries_path, 
  :method => :post, 
  :with => "$('entry_form').serialize()", 
  :success => "$('entry_edit').hide(); 
    $('entry_preview').show(); 
    $('preview_button').hide(); 
    $('edit_button').show();"
  }, {:id => :preview_button} %>

The controller action is pretty simple. I want to show the date when the post was created, so I just set up the data in the controller.

def preview
  @entry = Entry.new(params[:entry])
  @entry.created_at = Time.now
  render :layout => false
end

And here is the view for the action:

<div class="preview">
<div class="preview_title">Entry preview</div>
  <h1><%=h @entry.title %></h1>
  <h2><%=h @entry.tag_names %></h2>
  <h3><%=h @entry.created_at.to_s(:short) %></h3>
  <p><%=h @entry.content %></p>
</div>

Okay, by now we can see the preview of the post, but we would also like to be able to get back to editing. This is much simpler. First, we need a button called ‘Edit’, right next to the ‘Create’ and ‘Preview’ buttons. Only this time we don’t need AJAX, plain Javascript will do:

<%= button_to_function :Edit, :id => :edit_button do |page|
  page[:entry_preview].hide
  page[:entry_edit].show
  page[:edit_button].hide
  page[:preview_button].show
end %>

Let’s hide the ‘Edit’ button so that it will appear only after the ‘Preview’ button was pressed:

<script type="text/javascript">
  $('edit_button').hide();
</script>

And finally we need to set up a proper route in config/routes.rb file:

map.resources :entries, :collection => {:preview => :put}

That’s all, you can now admire your previews!