Rails plugins / Plugin tools
From WhyNotWiki
[edit] Plugins for creating plugins / plugin tools/extensions / more powerful plugins
[edit] Alternative to Engines: plugin_dependencies, loaded_plugins, plugin_migrations, plugin_assets, appable_plugins, and plugin_routing
http://www.pluginaweek.org/2006/12/14/rails-engines-vs-6-plugins/
Our plugins aren’t meant to altogether replace Engines. They are a means of appealing to those who don’t like Engines so that we can all continue to develop plugins that add migrations, models, controllers, helpers, etc. and everyone can use them, engine-lovers and engine-haters alike.
If you’ve come so far as to like each of our 6 plugins and use them all together, then this boils down to close to the same functionality that Engines offers.
You can either install them individually or all at once using the "Plugins plus" plugin bundle.
[edit]
Plugins plus
| Homepage: | http://wiki.pluginaweek.org/Plugins_plus [1] |
|---|---|
| Source code: | gem install plugins_plus or http://svn.pluginaweek.org/trunk/plugins/rails/plugins_plus
|
I've been using most of the plugins contained in plugins_plus individually for a while now, so I was excited to see a single plugin that would save me from installing each one individually!
Installation:
gem install plugins_plus config/environment.rb require 'plugins_plus' ... Rails::Initializer.run do |config| ...
[edit] Problem: Can't load as gem
[link to mailing list...]
First I tried the gem version, because gems seem the most convenient to me...
I started a brand-new Rails application so that there could be no other variables.
> ./script/about About your application's environment Ruby version 1.8.5 (i386-linux) RubyGems version 0.9.2 Rails version 1.2.3 Active Record version 1.15.3 Action Pack version 1.13.3 Action Web Service version 1.2.3 Action Mailer version 1.3.3 Active Support version 1.4.2 Application root /home/tyler/code/applications/t Environment development Database adapter mysql > gem list plugins_plus plugins_plus (0.1.0)Following the simple instructions at http://svn.pluginaweek.org/trunk/plugins/rails/plugins_plus/README , I added this near the top of my environment.rb:
require 'plugins_plus'This is what I got when I did ./script/server:
NameError: undefined method `initialize_schema_information' for module `ActiveRecord::ConnectionAdapters::SchemaStatements' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/module/aliasing.rb:28:in `alias_method' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/core_ext/module/aliasing.rb:28:in `alias_method_chain' /usr/lib/ruby/gems/1.8/gems/plugin_migrations-0.1.0/lib/plugin_migrations/extensions/schema_statements.rb:13 /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require' /usr/lib/ruby/gems/1.8/gems/plugin_migrations-0.1.0/lib/plugin_migrations.rb:3 /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require' /usr/lib/ruby/gems/1.8/gems/plugins_plus-0.1.0/lib/plugins_plus.rb:2 /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `gem_original_require' /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `require' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in' /usr/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require' /home/tyler/code/applications/t/config/environment.rb:13As you know, initialize_schema_information is defined in:
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/abstract/schema_statements.rb:235So it looks like somehow it ended up trying to load the plugin before active_record/connection_adapters/abstract/schema_statements.rb ever got called, which is kind of curious...
Sure enough, I threw some debug output in
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/abstract/schema_statements.rband tried starting the server but DIDN'T SEE the debug output.Suspecting that perhaps the reason it wasn't loading active_record/connection_adapters/abstract/schema_statements.rb was because I didn't have any models that _used_ AR in my app, I tried to generate a model... but got a DIFFERENT error:
> ./script/generate model whatever /usr/lib/ruby/gems/1.8/gems/loaded_plugins-0.1.0/lib/loaded_plugins/loaded_plugins.rb:4: undefined method `mattr_accessor' for PluginAWeek::LoadedPlugins:Module (NoMethodError) from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from /usr/lib/ruby/gems/1.8/gems/loaded_plugins-0.1.0/lib/loaded_plugins.rb:3 from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from /usr/lib/ruby/gems/1.8/gems/plugins_plus-0.1.0/lib/plugins_plus.rb:1 from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `gem_original_require' from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `require' from ./script/../config/../config/environment.rb:13
- Stopped requiring 'plugins_plus'
- ./script/generate model whatever
- rake db:migrate
- * I DID see the output from active_record/connection_adapters/abstract/schema_statements.rb during the migrate
- ./script/server
- * Did NOT see any output from active_record/connection_adapters/abstract/schema_statements.rb
- requiring 'plugins_plus' again
- ./script/server
- * Did NOT see any output from active_record/connection_adapters/abstract/schema_statements.rb
- * Still got same undefined method `initialize_schema_information' error.
Any suggestions?
[edit] Caveat: Must install using the ./script/plugin install -x option=
[link to mailing list...]
Next I tried installing it as a non-gem plugin:
./script/plugin install http://svn.pluginaweek.org/trunk/plugins/rails/plugins_plus + ./plugins_plus/CHANGELOG + ./plugins_plus/MIT-LICENSE + ./plugins_plus/README + ./plugins_plus/Rakefile + ./plugins_plus/init.rb + ./plugins_plus/lib/plugins_plus.rb + ./plugins_plus/tasks/plugins_plus_tasks.rakeWeird! Why aren't there more files in lib??
Looking at http://dev.pluginaweek.org/browser/trunk/plugins/rails/plugins_plus/lib , I see the reason:
Property svn:externals set to appable_plugins http://svn.pluginaweek.org/trunk/plugins/rails/appable_plugins loaded_plugins http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins partial_plugin_list http://svn.pluginaweek.org/trunk/plugins/rails/partial_plugin_list plugin_assets http://svn.pluginaweek.org/trunk/plugins/action_pack/plugin_assets plugin_dependencies http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies plugin_migrations http://svn.pluginaweek.org/trunk/plugins/active_record/migrations/plugin_migrations plugin_routing http://svn.pluginaweek.org/trunk/plugins/action_pack/plugin_routingMy app isn't _in_ a repository because it's just a throwaway app for test purposes.
I suggest putting a note in your readme that your application MUST be in a Subversion repository and you MUST install it using the -x option if you want the dependee plugins to be installed automatically!
Further evidence that this plugin will only work if those externals are in place: script/../config/../vendor/plugins/plugins_plus/init.rb:
base_path = File.dirname(__FILE__) configuration.plugin_paths << "#{base_path}/lib" load_plugin "#{base_path}/lib/partial_plugin_list" load_plugin "#{base_path}/lib/loaded_plugins" load_plugin "#{base_path}/lib/plugin_migrations" load_plugin "#{base_path}/lib/plugin_assets" load_plugin "#{base_path}/lib/appable_plugins" load_plugin "#{base_path}/lib/plugin_routing" load_plugin "#{base_path}/lib/plugin_dependencies"
~/code/applications/t > svn add ../t > ./script/plugin remove plugins_plus > ./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/plugins_plus ... Fetching external item into '/home/tyler/code/applications/t/vendor/plugins/plugins_plus/lib/appable_plugins' ... > ./script/server ...Seems to work!
Incidentally, I'm still NOT seeing any output from active_record/connection_adapters/abstract/schema_statements.rb , but that doesn't seem to matter. SOMEHOW initialize_schema_information is getting defined, as this test verifies...
./vendor/plugins/plugins_plus/lib/plugin_migrations/lib/plugin_migrations/extensions/schema_statements.rb
require 'pp' pp ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods.grep(/initialize_schema_information/) alias_method_chain :initialize_schema_information, :plugins=> ["initialize_schema_information", "initialize_schema_information_with_plugins"]The plugin install worked both with this line and without:
config.plugins = [ 'plugins_plus', '*'
[edit]
Appable plugins
| Homepage: | http://wiki.pluginaweek.org/Appable_plugins |
|---|---|
| Documentation: | Readme |
| Source code: | http://svn.pluginaweek.org/trunk/plugins/rails/appable_plugins |
| Project/Development: | http://dev.pluginaweek.org/browser/trunk/plugins/rails/appable_plugins
|
| Description: | appable_plugins adds the ability for plugins to share models, controllers, and helpers with your Rails application. Classes are automatically mixed in with your own models/controllers/helpers. |
| Depends on: | [[:Plugins:
|
[edit] Installation
./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins/
./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies
./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/appable_plugins
(The indentation is an attempt at making it look like an upside-down dependency tree.)
You need to make sure plugin_dependencies is loaded first.
[edit] Examples
http://wiki.pluginaweek.org/Appable_plugins.
acts_as_commentable/ acts_as_commentable/app/ acts_as_commentable/app/models/ acts_as_commentable/app/models/comment.rb acts_as_commentable/lib/ acts_as_commentable/lib/acts_as_commentable.rb acts_as_commentable/init.rbIf you, as a user of this plugin, want to then add additional methods or even override methods from the acts_as_commentable plugin, you would simply create a file named comment.rb as you normally would in your application's app/models/ folder. For example,
my_app/ my_app/app/ my_app/app/models/ my_app/app/models/comment.rb[...]
The order in which multiple models/controllers/helpers are loaded is based on the order in which the plugins were loaded. So in this example, since there was only 1 plugin, the Comment model in acts_as_commentable will be loaded first and then your application's Comment model.
[edit]
Plugin assets
| Homepage: | http://wiki.pluginaweek.org/Plugin_assets |
|---|---|
| Documentation: | Readme |
| Source code: | http://svn.pluginaweek.org/trunk/plugins/action_pack/plugin_assets |
| Project/Development: | http://dev.pluginaweek.org/browser/trunk/plugins/action_pack/plugin_assets
|
| Description: | adds the ability to automate the copying of plugin assets into your application's public/ folder, in addition to providing tasks for semi-automatically performing updates. |
| Depends on: | [[:Plugins:
|
[edit] Installation
./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins/ ./script/plugin install -x http://svn.pluginaweek.org/trunk/plugins/action_pack/plugin_assets
(The indentation is an attempt at making it look like an upside-down dependency tree.)
[edit] Usage
rake assets:list rake assets:update -- skips those that already exist rake assets:copy -- overwrites if already exist
[edit]
Loaded plugins
| Homepage: | http://wiki.pluginaweek.org/Loaded_plugins |
|---|---|
| Source code: | http://svn.pluginaweek.org/trunk/plugins/rails/loaded_plugins/
|
| As listed in other directories: | http://rubyfurnace.com/plugins/loaded_plugins , http://www.agilewebdevelopment.com/plugins/betternestedset
|
http://wiki.pluginaweek.org/Loaded_plugins
loaded_plugins adds a global variable $LOADED_PLUGINS to the Rails environment that lists the paths to the base directory of each plugin that was loaded during initialization. The paths are listed in the order in which they were loaded. Once initialization is complete, $LOADED_PLUGINS is frozen to prevent it from accidentally being overwritten.
[edit]
Plugin dependencies
[edit] Motivation
http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies/README (modified)
The current convention within Rails is to load plugins in alphabetical order. This poses a problem when certain plugins must be loaded before others.
For example, suppose you write a plugin called acts_as_addressable that uses the acts_as_enumerated plugin by Trevor Squires at http://svn.protocool.com/rails/plugins/enumerations_mixin/. You would then have a directory structure like the following:
vendor/ vendor/plugins vendor/plugins/acts_as_addressable vendor/plugins/acts_as_enumeratedOrdered alphabetically, acts_as_addressable will be loaded BEFORE acts_as_enumerated. This could potentially cause issues if you were assuming in your plugin that acts_as_enumerated had already been loaded.
...
This plugin addresses these issues by giving all plugins/gems the ability to define what other plugins they depend on using a similar API to that of RubyGems.
[edit] Usage
http://svn.pluginaweek.org/trunk/plugins/rails/plugin_dependencies/README
For example, the acts_as_addressable.rb would look like the following:
acts_as_addressable/lib/acts_as_addressable.rb: require_plugin 'acts_as_enumerated' ...When Rails is initialized, even though
acts_as_addressable.rbwill be executed first, the require does two things:
- Ensure that the acts_as_enumerated plugin is present. If it's not, an exception will be thrown.
- Load the acts_as_enumerated plugin and then continue initialization of the acts_as_addressable plugin.
This gives plugin developers the ability to add descriptive information about dependencies directly within their plugins rather than forcing the load order based on the directory names.
[edit] Installation
Option 1: As a gem (Preferred by User:Tyler)
> sudo gem install plugin_dependencies config/environment.rb: require 'plugin_dependencies' Rails::Initializer.run do |config| ...
(It seems allowable to have it installed as a plugin in addition to having it installed as a gem. This might be advantageous in order to ensure that ./vendor/plugins/plugin_dependencies/tasks/plugin_dependencies_tasks.rake is loaded. But I don't know what plugin_dependencies_tasks.rake is for, so I can't comment on whether that's necessary or not.)
Option 2: As a plugin
This plugin must be loaded before any plugins that use it:
config.plugins = ['plugin_dependencies'] + Dir.new('vendor/plugins').entries.reject {|f| f =~ /^\./}
(See Rails plugins and libraries / Installing and using#Specifying_load_order for details.)
[edit] Problem: undefined method `mattr_accessor'
I'd been using the plugin_dependencies gem before without problems (I thought), and it seems like I'm still able to start the server when I have a require 'plugin_dependencies' in environment.rb . HOWEVER, I get these errors, respectively, when I try to run ./script/about and ./script/console, and I'm not sure why...
> ./script/about /usr/lib/ruby/gems/1.8/gems/plugin_dependencies-0.1.0/lib/plugin_dependencies/plugin_dependencies.rb:3: undefined method `mattr_accessor' for PluginAWeek::PluginDependencies:Module (NoMethodError) from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from /usr/lib/ruby/gems/1.8/gems/plugin_dependencies-0.1.0/lib/plugin_dependencies.rb:1 from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `gem_original_require' from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:33:in `require' from ./script/../config/../config/environment.rb:14> ./script/console Loading development environment. /usr/lib/ruby/gems/1.8/gems/plugin_dependencies-0.1.0/lib/plugin_dependencies/plugin_dependencies.rb:3:NoMethodError: undefined method `mattr_accessor' for PluginAWeek::PluginDependencies:Module /usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/selector_assertions.rb:525:NoMethodError: undefined method `camelize' for "top":String ./script/../config/../config/../app/controllers/application.rb:4:NameError: uninitialized constant ActionController::Base Welcome! irb -> (Ctrl-D)Loaded suite irb Started Finished in 0.000663 seconds. 0 tests, 0 assertions, 0 failures, 0 errors(Not sure why it's trying to run a test suite there?!)
Fortunately, I can just fall back to using the non-gem version with plugins_plus and everything works fine.
[edit] Plugems
| Project/Development: | http://rubyforge.org/projects/plugems/
|
|---|---|
| Description: | Rails framework for fully 'gemified' applications and shared dependencies. Dependency management, views, rake tasks, configuration files, etc. supported directly via Rubygems. Has proved critical for us for large-scale enterprise Rails development.
|
| Readiness: | (Probably has a gem though) This Project Has Not Released Any Files 2007-03-23 17:10, Registered: 2007-02-16 13:24
|
[edit] Plugin migrations
See Rails plugins and libraries / Database-level#Plugin migrations
[edit] [Engines (category)]: more powerful plugins
Rails Engines are a way of dropping in whole chunks of functionality into your existing application without affecting any of your existing code. They could also be described as application aspects, or vertical application slices – top-to-bottom units which provide full MVC coverage for a certain, specific application function.
Engines can be as lightweight as the simplest plugin, or as full-featured as your your imagination can conceive. They are a natural successor to Rails' original Generator mechanism, or alternatively, plugins with all the power you could ever hope for.
http://rails-engines.org/faq/components-vs-plugins-vs-engines/:
- Engines are also useful when you have an entire 'subsystem' of a Rails application (such as managing users & permissions) where you have model objects, controllers to manipulate/administer those objects (updating, creating new ones) and a full set of views & helpers to display information about those objects. Engines are like a slice of an application from top (views/helpers) to bottom (models) which can be dropped into an existing application and appear as if they always existed in the normal /app directory. Developers can selectively override parts of Engines as they need to handle their application (such as changing the user/home view to display a silly name), without affecting the rest of the Engine).
[edit] Engines: Better than generators
http://rails-engines.org/faq/engines-vs-generators/:
- The engines plugin extends Rails' own minimal plugin system just enough to allow you to include in your plugin almost any type of file you might find in a regular Rails application: controllers, views, helpers, libraries, models, schemas, tests, stylesheets and javascripts... anything you can think of, essentially.
- These files are contained within a single directory inside /vendor/plugins, completely isolating them from the rest of your application and therefore making it trivial to update to new versions.
- It is still crucial that you as the developer be allowed to alter the behaviour of this packaged code to suit the individual needs of your application. With this in mind, the Engines plugin allows you to override the behaviour of engine code in a simple and clear way:
-
- single views can be provided which are automatically used instead of those provided with the engine
- controller actions can be overridden individually in your application, isolating your custom code from the underlying default implementation
- model and library code is normally provided as a ruby Module, making it simple to include in your own custom Models
- Developing an engine is a much more natural process, compared to creating generators - there is no 'ERb translation step', and changes to an engine can be made and committed in one application and then propagated to another application with no intermediate stages. Engine code looks exactly like normal Rails application code, making it intuitive to skim when you are examining an engine's behavior.
[edit] Information about creating/writing plugins
[edit] [Ruby-general] Problem: loading a file can have side-effects; make it possible to load the file without those side-effects; in other words, two-stage initialization
You'd want to be able to do something like this:
SomeModule::SomeClass::do_the_usual_initialization = false require 'some_class'
But: You can't do that before SomeModule::SomeClass have been defined. And it won't be defined until we load the file which contains their definition! But we can't do that without getting the unwanted side-effects, which is why we were doing the SomeModule::SomeClass::do_the_usual_initialization = false in the first place, to prevent those side-effects.
Catch 22.
Solution: Create dummy modules/classes.
Easiest way to do that?
Class.new(:name => :SomeClass, :parent => :SomeModule)::do_the_usual_initialization = false require 'some_class'
(see Ruby libraries / Core#Module creation helper)
Would that work?
I think it would.
[edit] acts_as plugins
Bruce Tate (2007-03-13). Crossing borders: Extensions in Rails: The anatomy of an acts_as plug-in (http://www-128.ibm.com/developerworks/java/library/j-cb03137/index.html).
module ActMacro # Configuration options are # # * +column+ - specifies the column name to use for keeping the state (default: state) # * +initial+ - specifies an initial state for newly created objects (required) def acts_as_state_machine(opts) self.extend(ClassMethods) raise NoInitialState unless opts[:initial] write_inheritable_attribute :states, {} write_inheritable_attribute :initial_state, opts[:initial] write_inheritable_attribute :transition_table, {} write_inheritable_attribute :event_table, {} write_inheritable_attribute :state_column, opts[:column] || 'state' class_inheritable_reader :initial_state class_inheritable_reader :state_column class_inheritable_reader :transition_table class_inheritable_reader :event_table self.send(:include, ScottBarron::Acts::StateMachine::InstanceMethods) before_create :set_initial_state after_create :run_initial_state_actions end end...
Go back to the [write_inheritable_attribute and class_inheritable_reader macros (category)]. You may be wondering why the module doesn't use simple inheritance. The reason is simple: The module has an inheritance hierarchy of its own. These macros allow the module to project these attributes onto the target class -- Nonprofit in this example. The most important attributes are state_column and a series of transition tables containing the states, events, and transitions. Now it's time to add the class methods that form the DSL.
[edit] Information about creating/writing plugins: Testing plugins
Rails plugins and libraries / Testing plugins edit
[edit] test_helper files / Test initialization
[edit]
Example from acts_as_ordered_tree
Notable features:
- Depends on parent app's Rails "environment" (boot.rb) but provides own database and schema. (Bad: Means it can only be tested when installed as plugin within context of an app.)
- Uses sqlite3 (in memory), so:
- it doesn't affect the parent app's test database (so that doesn't have to be reloaded when the plugin test is finished),
- the user of the plugin doesn't need to do any extra configuration to run tests,
- and it doesn't even litter the filesystem with any database files!
./vendor/plugins/acts_as_ordered_tree/test/abstract_unit.rb
ENV["RAILS_ENV"] = "test" require File.dirname(__FILE__) + '/../../../../config/boot' require 'rubygems' require 'test/unit' # The only part of Rails that is actually needed, apparently require 'active_record' # Use a special database for this plugin tests. Output to a local log file. config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log') ActiveRecord::Base.establish_connection(config['database']) # Load the plugin itself require File.dirname(__FILE__) + '/../init' # An ActiveRecord model require File.dirname(__FILE__) + '/../lib/person' # Basically equivalent to a migration. Creates the schema/tables. load(File.dirname(__FILE__) + '/schema.rb')
vendor/plugins/acts_as_ordered_tree/test/database.yml
database: adapter: sqlite3 database: ":memory:"
vendor/plugins/acts_as_ordered_tree/test/schema.rb
ActiveRecord::Schema.define(:version => 1) do
create_table "people", :force => true do |t|
t.column "parent_id" ,:integer ,:null => false ,:default => 0
t.column "position" ,:integer
t.column "name" ,:string
end
add_index "people", ["parent_id"], :name => "index_people_on_parent_id"
end
vendor/plugins/acts_as_ordered_tree/lib/person.rb
class Person < ActiveRecord::Base acts_as_ordered_tree end
