To generate this sort of complex form for two of your models you’ll first need to install my “repeated_auto_complete” gem from gemcutter.org:
$ gem sources -a http://gemcutter.org http://gemcutter.org added to sources $ sudo gem install repeated_auto_complete Successfully installed repeated_auto_complete-0.1.0 1 gem installed Installing ri documentation for repeated_auto_complete-0.1.0... Installing RDoc documentation for repeated_auto_complete-0.1.0...
To learn more about repeated_auto_complete and what it does, see: https://patshaughnessy.net/repeated_auto_complete. Now you can generate a complex form like the one shown above for two of your models in a has_many/belongs_to, has_and_belongs_to_many or has_many, :through association by installing View Mapper (version 0.3.1 or later):
$ sudo gem install view_mapper Successfully installed view_mapper-0.3.1 1 gem installed Installing ri documentation for view_mapper-0.3.1... Installing RDoc documentation for view_mapper-0.3.1...
… and then running the “view_for” generator with a view option called “has_many_auto_complete,” like this:
./script/generate view_for group --view has_many_auto_complete:people
Detailed Example
To see how easy it is to create a complex form using View Mapper, let’s create one from scratch in a brand new Rails app. You should be able to follow along using the commands below on your machine. First, let’s create a new Rails application:
$ rails complex_auto_complete create create app/controllers create app/helpers create app/models create app/views/layouts create config/environments create config/initializers create config/locales … etc.. create log/server.log create log/production.log create log/development.log create log/test.log
The first thing I’ll do is install the auto_complete plugin. However, since I’m planning to use auto_complete on a complex form, I’ll need to get my fork of auto_complete which I’ve deployed as a gem on gemcutter.org:
$ gem sources -a http://gemcutter.org http://gemcutter.org added to sources $ sudo gem install repeated_auto_complete Successfully installed repeated_auto_complete-0.1.0 1 gem installed Installing ri documentation for repeated_auto_complete-0.1.0... Installing RDoc documentation for repeated_auto_complete-0.1.0...
And let’s update my new app to use the repeated_auto_complete gem by editing the config/environment.rb file:
Rails::Initializer.run do |config| …etc… config.gem "repeated_auto_complete" …etc…
If you prefer, you can also install this the old fashioned way, using “script/plugin install git://github.com/patshaughnessy/auto_complete.git”. Next, let’s generate a new model called “person” with a couple of fields for name and age, like the ones shown above in the screen shot:
$ cd complex_auto_complete/ $ ./script/generate model person name:string age:integer group_id:integer 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/20091125195040_create_people.rb
Note that I’ve also included an integer field for the group id, since in a minute I’ll be adding a belongs_to association for people to groups.
Now I’m ready to use View Mapper… if you haven’t installed that yet, get it from gemcutter.org like this:
$ sudo gem install view_mapper Successfully installed view_mapper-0.3.1 1 gem installed Installing ri documentation for view_mapper-0.3.1... Installing RDoc documentation for view_mapper-0.3.1...
You’ll need at least version 0.3.1 to use auto_complete on a complex form. Now I can use View Mapper to create scaffolding for a new “group” model that has many people with auto_complete like this:
$ ./script/generate scaffold_for_view group name:string --view has_many_auto_complete:people error Table for model 'person' does not exist - run rake db:migrate first.
Yes… I forgot to create the people table in my database; if we do that:
$ rake db:migrate (in /Users/pat/rails-apps/complex_auto_complete) == CreatePeople: migrating =================================================== -- create_table(:people) -> 0.0014s == CreatePeople: migrated (0.0015s) ==========================================
… and then re-run View Mapper:
$ ./script/generate scaffold_for_view group name:string --view has_many_auto_complete:people warning Model Person does not contain a belongs_to association for Group.
… we get a second error message! This time View Mapper is reminding me that I still need to add “belongs_to :group” to the person model in order to get the complex form to work. Let’s do that now:
class Person < ActiveRecord::Base belongs_to :group end
And now I can run View Mapper once more:
$ ./script/generate scaffold_for_view group name:string --view has_many_auto_complete:people exists app/models/ …etc… create app/models/group.rb create test/unit/group_test.rb create test/fixtures/groups.yml exists db/migrate create db/migrate/20091125195715_create_groups.rb create app/views/groups/show.html.erb create app/views/groups/_form.html.erb create app/views/groups/_person.html.erb create public/javascripts/nested_attributes.js route map.connect 'auto_complete_for_group_name', :controller => 'groups', :action => 'auto_complete_for_group_name' route map.connect 'auto_complete_for_person_name', :controller => 'groups', :action => 'auto_complete_for_person_name' route map.connect 'auto_complete_for_person_age', :controller => 'groups', :action => 'auto_complete_for_person_age'
Now you can see the new scaffolding files View Mapper created, including some new scaffolding files peculiar to complex forms, like “nested_attributes.js,” “_form.html.erb,” and “_person.html.erb.” You may also have noticed View Mapper added three new routes related to the auto_complete plugin; these will handle the AJAX requests used to return the auto_complete options to the form.
Now to get it all to work, I just need to create the group table:
$ rake db:migrate (in /Users/pat/rails-apps/complex_auto_complete) == CreateGroups: migrating =================================================== -- create_table(:groups) -> 0.0013s == CreateGroups: migrated (0.0014s) ==========================================
Now running my server and creating a new group I see:
If you click “Add a Person” you’ll see nested fields for new Person records appear. This all works exactly the same way as the standard nested attributes scaffolding that I described in my last post. The only difference is that in this form, each of the text fields present in both the parent (“Group”) and child (“Person”) models are displayed using the “text_field_with_auto_complete” method.
I’ll try to write up a detailed walk through of how this scaffolding actually works as soon as I can… there are a lot of interesting details in the code that will be fun to look at. In the meantime, hopefully this scaffolding will make it easier for you to learn how to use auto_complete and nested attributes together in your app.