Auto_complete scaffolding

I’ve written a lot here about the Rails auto_complete plugin; I’ve also refactored the auto_complete plugin to support repeated fields and named scopes. Today I’d like to show how you can automatically generate Rails view and controller code with auto_complete behavior for one of your models using a new gem I’ve written called View Mapper. If you’ve never used the auto_complete plugin before this is a great way to learn quickly how to use it in your app; even if you are familiar with the plugin using scaffolding like this can help to get a working auto_complete form up and running quickly and let you concentrate on more important parts of your app.

Let’s say you have an existing model in your app called “Person:”

Class Person < ActiveRecord::Base
end

And suppose the Person model has two string attributes for the person’s name and the name of the office they work in:

class CreatePeople < ActiveRecord::Migration
  def self.up
    create_table :people do |t|
      t.string :name
      t.string :office
      etc…

Now let’s install View Mapper so we can generate an auto_complete view for our person model. Since I’ve only deployed view_mapper on gemcutter.org for now, you’ll also need to add gemcutter as a gem source if you haven’t already.

$ gem sources -a http://gemcutter.org
http://gemcutter.org added to sources
$ sudo gem install view_mapper
Successfully installed view_mapper-0.1.0
1 gem installed
Installing ri documentation for view_mapper-0.1.0...
Installing RDoc documentation for view_mapper-0.1.0...

Now with view_mapper you can run a single command to generate scaffolding that displays the your existing person model’s fields in a form with auto_complete type ahead behavior for the office field:

$ ./script/generate view_for person --view auto_complete:office
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/people
      exists  app/views/layouts/
      exists  test/functional/
      exists  test/unit/
      create  test/unit/helpers/
      exists  public/stylesheets/
      create  app/views/people/index.html.erb
      create  app/views/people/show.html.erb
      create  app/views/people/new.html.erb
      create  app/views/people/edit.html.erb
      create  app/views/layouts/people.html.erb
      create  public/stylesheets/scaffold.css
      create  app/controllers/people_controller.rb
      create  test/functional/people_controller_test.rb
      create  app/helpers/people_helper.rb
      create  test/unit/helpers/people_helper_test.rb
       route  map.resources :people
       route  map.connect 'auto_complete_for_person_office',
                          :controller => 'people',
                          :action => 'auto_complete_for_person_office'

This works just like the Rails scaffold generator, except that the view_for generator has also:

  • inspected your person model and found the name and office columns.
  • added a route for “auto_complete_for_person_office” to routes.rb.
  • added a call to “auto_complete_for :person, :office” to PersonController.
  • used text_field_for_auto_complete on the office field in your new and edit forms.
  • inserted “javascript_include_tag :defaults” into views/layouts/people.html.erb to load the prototype javascript library.

If you start up your application and create a few person records with names and addresses, then you will see the auto_complete plugin working!

With this working example right inside your application, you can easily review exactly how the view, route and controller files use auto_complete. After that you can adapt the view to fit into your application’s design and delete the scaffolding you don’t really need or want.

As another example, let’s create an entirely new Rails application completely from scratch, and use View Mapper to setup auto_complete inside it:

$ rails auto_complete_example
      create  
      create  app/controllers
      create  app/helpers
      create  app/models
      create  app/views/layouts
      etc…
$ cd auto_complete_example

First, let’s install the auto_complete plugin. (In a future post I’ll show how to use View Mapper with my fork of auto_complete in a complex form.)

$ ./script/plugin install git://github.com/rails/auto_complete.git
Initialized empty Git repository in /Users/pat/rails-apps/auto_complete_example/vendor/plugins/auto_complete/.git/
remote: Counting objects: 13, done.
remote: Compressing objects: 100% (12/12), done.
remote: Total 13 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (13/13), done.
From git://github.com/rails/auto_complete
 * branch            HEAD       -> FETCH_HEAD

Now that we have the plugin installed, let’s create our scaffolding. Along with the “view_for” generator I used above, View Mapper also provides a generator called “scaffold_for_view.” This works the same way, except it just creates a new model the same way the Rails scaffold generator does, instead of inspecting an existing model.

Let’s create the same person model we used above, and an auto_complete view:

$ ./script/generate scaffold_for_view person name:string office:string
                                      --view auto_complete:office
      exists  app/models/
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/people
      exists  app/views/layouts/
      exists  test/functional/
      exists  test/unit/
      create  test/unit/helpers/
      exists  public/stylesheets/
      create  app/views/people/index.html.erb
      create  app/views/people/show.html.erb
      create  app/views/people/new.html.erb
      create  app/views/people/edit.html.erb
      create  app/views/layouts/people.html.erb
      create  public/stylesheets/scaffold.css
      create  app/controllers/people_controller.rb
      create  test/functional/people_controller_test.rb
      create  app/helpers/people_helper.rb
      create  test/unit/helpers/people_helper_test.rb
       route  map.resources :people
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
      create    app/models/person.rb
      create    test/unit/person_test.rb
      create    test/fixtures/people.yml
      create    db/migrate
      create    db/migrate/20091001161349_create_people.rb
       route  map.connect 'auto_complete_for_person_office',
                          :controller => 'people',
                          :action =>'auto_complete_for_person_office'

Note the syntax is the same as the standard Rails scaffold generator, except I’ve added the “view” parameter to specify we want the auto_complete plugin to be used in the view.

Now we just need to migrate the database schema and run our app:

$ rake db:migrate
(in /Users/pat/rails-apps/auto_complete_example)
==  CreatePeople: migrating ===================================================
-- create_table(:people)
   -> 0.0012s
==  CreatePeople: migrated (0.0015s) ==========================================

And if you add a few records, you’ll see auto_complete working!

I’ll be adding more views to View Mapper soon, and in future posts here I’ll write about how to generate scaffolding for Paperclip file attachments, my version of auto_complete used on a complex form, and also how to write your own views for View Mapper.