I'm building a Rails app for a client that will be used only by expert users (never the general public). These users will spend a lot of time on my forms, and my client and I want to streamline the data entry process and make their lives a little less painful. In this case, it means putting a new model form on nearly all the Index views, and removing the Show view. Here's what you save over the standard scaffold flow that the built-in Rails generator gives you:
- No click on New Item
- No New Item view
- No Show view
- No Back button to see the list again
- No click on New Item to get the blank form again
That's three clicks and three trips to the server, which is really handy if you're entering a lot of data.
There are a couple of tricks to ensure routing is correct when handling validation failures.
For my example, consider musical albums, each having a title. Starting with a blank Rails app, I'll generate my scaffold:
$ script/generate scaffold album title:string
You can now perform all the standard CRUD steps as you'd expect. To get validation to sometimes fail, let's update the model to ensure that title isn't blank:
class Album < ActiveRecord::Base
validates_presence_of :title
end
To get the new form on the index view, there are just a few steps to complete.
- Put the form in the view. Copy and paste the form in albums/new.html.erb into albums/index.html.erb for this exercise. Use a partial for your production code.
- Update the controller so the #index action creates a new album, but leave the collection find in place, so you also get the list of existing albums.
- Update the #create action so that if validation fails, you render the #index view instead of #new.
- Change the successful create so it redirects to the index.
- Since #create will show the index , you need to fetch the same collection of albums done there.
The complete updated #create action:
def create
@albums = Album.all
@album = Album.new(params[:album])
respond_to do |format|
if @album.save
flash[:notice] = 'Album was successfully created.'
format.html { redirect_to(albums_path) }
format.xml { render :xml => @album, :status => :created, :location => @album }
else
format.html { render :action => "index" }
format.xml { render :xml => @album.errors, :status => :unprocessable_entity }
end
end
end
I also redirected successful updates back to the index to shorten that trip too.
That's all there is to it. In the next post, I'll show you how to do it when you have models with nested resources.
Comments