When you are begging with Ruby on Rails, you usually resort to scaffolding. Scaffolds are a quick way to boost your productivity, especially in Rails 2.0, which makes it possible to specify most details for scaffolding a RESTful resource.
.png)
A default "New post" form with a "Preview" button.
Using the default scaffold, you get a single "Create" (or "Update") button in your new post (or whatever resource you re working on) and edit post forms. In this post, I'll tell you how to add another button for previewing the post before saving it to the database.
In order to do this, you will need to keep in mind that a form is submitted to the server passing the data it contains. So, you don't keep the variables defined in your controllers (or view templates, for that matter).
If you want to know what parameters forms are passing look at the logs (the logs are displayed in the console where you ran your ./script/server script, or in the Output docker if you are in NetBeans). If you click on "Create" or "Edit", you will notice one paramter in the params hash. The key for the parameter is :commit and it's value corresponds to the value of the submit button. So, if you clicked "Create", you will have a parameter that looks like this:
Parameters: {"commit"=>"Create" ...
We will use this fact to create our Preview functionality.
Let's get started. I will assume you know how to scaffold resources, and how to map your root to 'posts' controller. Do that now. Scaffold a Post resource with title and body fields.
We will modify the PostsController to accommodate the preview functionality. Open the posts_controller.rb file located in your your_app/app/controllers. Take a look at the new method:
def new
@post ||= Post.new
@preview = false # add this line
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @post }
end
end
We added this line: @preview = false. This is a boolean variable which we will use in the new view template to determine whether to show the preview box or not.
Next, let's modify the create action.
def create
if params[:commit] == "Create" # we enclose the default code in the if conditional
@post = Post.new(params[:post])
respond_to do |format|
if @post.save
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to(@post) }
format.xml { render :xml => @post, :status => :created, :location => @post }
else
format.html { render :action => "new" }
format.xml { render :xml => @post.errors, :status => :unprocessable_entity }
end
end
else # and we add another case when the button is not "Create"
@post = Post.new(params[:post])
@preview = true
render :action => "new"
end
end
Don't be afraid of this rather large chunk, it's mostly the default code generated by scaffolding. First but the whole of the default code for create method between if params[:commit] == "Create" and else statements. What this does is read the :commit parameter from the params hash and if it says "Create" it means you clicked on "Create", so we do what we usually do: create the resource.
Next, put the above code between the else and end in place. What it does is map the params[:post] part of the params hash to a @post variable. We simply keep whatever the form returned when we clicked something else than "Create". We also set the @preview variable to true (you will see how it is used later on). Finally, we render the "new" template again. Keep in mind that we don't call the new action here, so our @preview is not reset to false when we render the template.
Now, let's edit the template. The template looks like this:
<h1>New post</h1>
<%= error_messages_for :post %>
<%- if @preview == true %> # add a conditional which displays the preview only when @preview == true
<div id="post_preview">
<%= @post.body %>
</div>
<% end -%>
<% form_for(@post) do |f| %>
<p>
<b>Title</b><br />
<%= f.text_field :title %>
<p>
<b>Body</b><br />
<%= f.text_area :body %>
</p>
<p>
<%= f.submit "Preview" %> # add this submit button
<%= f.submit "Create" if @preview == true %> # only render this button in preview mode
</p>
<% end %>
<%= link_to 'Back', posts_path %>
The additions are as follows.
The if conditional test is @preview is true (we set that in our controller, remember?). We render the preview box in a <div> tag only if the condition is met.
Next, we add a preview button. The name of the button can be anything because the controller only tests for "Create". And finally, we hide the "Create" button if @preview is set to false to force the user to preview the post at least once.
Save the files, migrate the database if you haven't done that yet, and test this. The "Create" button should appear once you click on preview, and the contents of your :body text area should appear just below the "New post" header.
Post new comment