Permalink
Browse files

Renamed the readme.

Forget the symlink: it seems that Github cannot cope with it.
  • Loading branch information...
1 parent 0270053 commit 562cd418e993425a894218529cc4f72c4582b35d @baldowl committed Jul 20, 2009
Showing with 484 additions and 485 deletions.
  1. +0 −484 README
  2. +0 −1 README.rdoc
  3. +484 −0 README.rdoc
View
484 README
@@ -1,484 +0,0 @@
-= Rails AutoAdmin Plugin
-
-== What is it?
-
-A plugin for Ruby on Rails that automagically creates an administration
-interface, based on your models. It is heavily inspired by the
-Django[http://www.djangoproject.com/] administration system, and the only
-theme currently available is based directly on Django's administration system.
-From the screenshots posted so far, it appears to share goals with
-Streamlined[http://streamlined.relevancellc.com/].
-
-
-== Example?
-
- class Customer < ActiveRecord::Base
- belongs_to :store
- has_many :payments, :order => 'payment_date DESC'
-
- def name; first_name + ' ' + last_name; end
-
- refresh_time 5
- sort_by :last_name
- search_by :first_name, :last_name
- filter_by :active, :store
- default_filter :active => true
- list_columns :store, :first_name, :last_name
-
- admin_fieldset do |b|
- b.text_field :first_name
- b.text_field :last_name
- b.auto_field :active
- b.select :store
- end
- admin_child_table 'Payments', :payments do |b|
- b.static_text :payment_date
- b.static_text :amount
- end
- end
-
-
-== What isn't it?
-
-Scaffolding. This is not a view generator for you to then customise. Either it
-provides the interface you want, or it doesn't. (With a limited, but hopefully
-expanding, set of exceptions.)
-
-For everyone. This is for applications that have a public interface and a
-restricted-access administrative interface. Its goal is not to generate views
-you would otherwise have to craft manually, so much as generating views you
-otherwise wouldn't bother to create. Of course, a neat side-effect of using
-this is that your boss (or your client's IT manager) can make simple
-database-level changes that would otherwise require a developer to use either
-the console or direct SQL. If you're trying to create an interface for all
-your users, this probably isn't for you.
-
-
-== Where is it?
-
-The public git repository is hosted by Github[http://github.com] and can be
-reached starting from http://github.com/baldowl/auto_admin
-
-I cannot stress enough that this is just a fork of the original code written
-by Matthew Draper; if you prefer the original version, then get it from the
-Subversion repository at http://svn.trebex.net/auto-admin/trunk/auto-admin
-
-
-== What does it assume?
-
-All objects it encounters can be usefully represented to a human as a string.
-It achieves this by adding a +to_label+ method to +Object+, which will return
-the first available of +label+, +name+, +to_s+ or +inspect+.
-
-Your access control requirements for the administration section are relatively
-"all or nothing". I intend to add simple class- and fieldset- level
-declarative permission checking soonish (whenever I start to need it). Access
-control based on querying individual objects should come at some point, but I
-don't anticipate needing that level of control any time soon. You can
-currently customise which fields are displayed (the field list is a block of
-code, after all), but will end up with empty fieldsets if you don't include
-any.
-
-If you have any access control (which I expect will pretty much always be the
-case), you must specify it with the <tt>admin_model=</tt> and
-<tt>admin_model_id=</tt> methods in the configuration block of AutoAdmin; the
-class must respond to +authenticate+, +login+, or
-+find_by_username_and_password+ and that method must take two strings and
-return +nil+ for failure or a non-false value for success. It *must* return
-the authenticated user's id (or, in a less ideal turn, the user object itself:
-we will extract the id by ourself) -- the id will be stored in the session
-using the key provided by +admin_model_id+ and the currently logged-in user
-will be looked for; if the returned value responds to one or more of
-<tt>active?</tt>, <tt>enabled?</tt>, <tt>disabled?</tt> or <tt>admin?</tt>,
-they will be treated appropriately. So if other parts of your site do the
-same, things will Just Work.
-
-
-=== History
-
-Admins' actions are automatically recorded and shown if the optional
-<tt>admin_histories</tt> table is available.
-
-See AutoAdminController#history for details.
-
-
-== What do you need?
-
-To use AutoAdmin with Rails 2.* you need an extra plugin,
-will_paginate[http://github.com/mislav/will_paginate], because the pagination
-mechanism has been removed from the Rails core base.
-
-To use the +text_field_with_auto_complete+ helper you need an extra plugin,
-auto_complete[http://github.com/rails/auto_complete], because the
-autocompletion mechanism has been removed from the Rails core base.
-
-For the optional export mechanism you also need:
-
-* the *faster_csv* gem for the CSV export module;
-
-* the <b>pdf-writer</b> gem for the PDF export module.
-
-
-== How do I use it?
-
-Initially (after installing the plugin, obviously), you need to add a few
-lines to the bottom of your environment.rb or in an initializer file:
-
- AutoAdmin.config do |admin|
- # This information is used by the theme to construct a useful
- # header; the first parameter is the full URL of the main site, the
- # second is the displayed name of the site, and the third (optional)
- # parameter is the title for the administration site.
- admin.set_site_info 'http://www.example.com/', 'example.com',
- 'Administration area for example.com'
-
- # "Primary Objects" are those for which lists should be directly
- # accessible from the home page.
- admin.primary_objects = %w(actor film user)
-
- admin.theme = :django # Optional; this is the default.
-
- # The configurable, optional access control system.
- admin.admin_model = Account
- admin.admin_model_id = :account_id
-
- # The optional export mechanism.
- admin.save_as = %w(pdf csv)
- end
-
-Having done that, you can now (re-)start <tt>script/server</tt>, and navigate
-to http://localhost:3000/admin/. Yes, it installs its own routes, but they are
-partially configurable; for now, just don't try to use <tt>/admin/</tt> for
-anything else.
-
-To customise which fields appear in the edit and list screens, you go on to...
-
-
-== How does it work? - Part I, Declarative UI definition
-
-The plugin adds a number of singleton methods to ActiveRecord::Base, which
-permit you to declare how the administration interface should behave.
-
-This set of methods, which are quite central to the utility of the plugin,
-have grown rather organically, over a period of time (as has my Ruby-fu). I've
-attempted to clear out the most glaring API inconsitencies, but it's still a
-bit of a mess. Some of the implementations definitely leave a bit to be
-desired. Cleaning this up is near the top of my TODO list. That said, it
-should all work. :)
-
-I really need to go through and write decent documentation for all the
-published methods, but for now, the following summary should at least act as a
-guide. Essentially, inside the model, you can use the following methods:
-
-[object_group(group_name)]
- Declares which 'object group' this object belongs to, for use in the
- interface. Currently, this is used to group together related objects on the
- index page.
-
-[refresh_time(seconds)]
- Instructs the list view to meta-refresh with the specified delay.
-
-[sort_by(column, reverse=false)]
- Instructs the list view to sort on the specified column by default.
-
-[search_by(*columns)]
- Add rudimentary text searching across the named columns. Note that this
- defines a <tt>MyModel.search(many, query, options={})</tt> wrapper around
- <tt>MyModel.find(many, options)</tt>.
-
-[filter_by(*columns)]
- Allow filtering of the list screen by the named columns (filtering currently
- works for: custom, boolean, date, belongs_to, has_one, and string). Note
- that the last three will do rather nasty and sub-optimal queries to
- determine the filter options.
-
-[default_filter(filters)]
- Takes a hash of (column, value) pairs, to default a filter to something
- other than 'All'.
-
-[filter_options_for(column, choices, &block)]
- Specifies a fixed set of choices to be offered as filter options instead of
- automatically working it out. Choices should be a (value, label) hash. The
- optional block will be given each value in turn, and should return an SQL
- condition fragment.
-
-[column_labels(labels)]
- Takes a hash of (column, label) pairs, to change the default label for a
- field to explicitly define the human label for a column. This label will be
- the default used in both list and edit views.
-
-[list_columns(*columns, &proc)]
- Takes either a simple-list of column names, or a Field Definition Block (see
- next section) or both.
-
- Please, note that a list of column names will produce a bunch of fields
- using the +static_text+ helper almost for everything but the first column
- (which will get a special treatment to allow you to access the "edit view").
- If a column occurs more than once (summing up the list of column names and
- the FDB), then that column will appear more than once:
-
- list_columns :name, :code, :address do |f|
- f.hyperlink :address
- end
-
- The previous code fragment will list the +address+ column twice: the first
- one will be shown as static text, the second one will produce a real link.
-
- At the moment, if you have a long list of columns and want to customize only
- a few of them, you have to write then down one by one, even those that don't
- need special care.
-
-[admin_fieldset(label='', *columns, &proc)]
- Defines a fieldset for edit views. For simple use, you can just give it a
- list of columns. Once you get started, you'll want to pass a Field
- Definition Block, though.
-
- In the Field Definition Block you can get hold of the model instance using
- the block's parameter; let's say the model has an attachment, handled by
- paperclip[http://github.com/thoughtbot/paperclip], called +picture+ and you
- want to show the image's URL like an hyperlink:
-
- admin_fieldset do |f|
- # ...
- f.hyperlink :picture, :url => f.object.picture.url
- end
-
- At the moment, this does not work with +list_columns+.
-
- Most of the helpers which accept or require a block will yield the model
- instance to the block, if it requires a parameter:
-
- admin_fieldset do |f|
- # ...
- f.static_image :picture do |cover|
- {:src => cover.picture.url}
- end
- end
-
- This works also with +list_columns+.
-
-[admin_child_table(label, collection, options={}, &proc)]
- Defines a fieldset for edit views, to show a table of items from a child
- collection. It uses a Field Definition Block to declare what columns should
- be shown. Generally, you'd want to use the static_text helper, I suspect.
- *WARNING*: This has no tests, and I'm almost certain it will break horribly
- if you try to use anything other than static_text.
-
-[admin_child_form(collection, options={}, &proc)]
- Defines a "fieldset" for edit views, to show *several* fieldsets, each
- containing one object from a child collection. It uses a Field Definition
- Block to declare what columns should be shown. I don't think it'd be wise to
- use this on a large collection, but it's your application. :) *WARNING*:
- This also has no tests, and I believe it will break horribly if you try to
- use it at all.
-
-
-== Field Definition Block?!?
-
-A number of the above methods provide for a block to declare what fields are
-to be shown. This is achieved by yielding a builder to the block. Depending on
-context, the mood of a theme author, and the phase of the moon, a given block
-will see several builders in its lifetime. Not all builders will have an
-active object; all will respond to the +object+ method, though. A basic field
-definition block will just call a field helper on the builder for each field
-that it wishes to display. The +auto_field+ helper (which automatically
-determines an appropriate field type based on column and association metadata)
-is available if you only want to specify the field type for some of the
-fields. All field helpers take <tt>(field_name, options={},
-*other_stuff)</tt>. Most just take the two parameters, and I'm considering
-deprecating the extra parameters on those that currently support them. Note
-that unlike a standard builder, you don't have to do anything with the return
-value; the theme's actual FormBuilder is wrapped by a DeclarativeFormBuilder,
-which takes care of that for you.
-
-In theory, there's no compelling reason you can't add complex logic to a field
-definition block, such as examining the current user, or even the builder's
-active object (though I strongly encourage you to handle nil permissively, at
-this stage). It would be unwise to vary the fields returned based on the
-object for a list view, for fairly obvious reasons.
-
-
-== Available Form Helpers
-
-* Simple helpers that just delegate to the ActionView's FormBuilder:
- +hidden_field+, +date_select+, +datetime_select+, +text_field+, +text_area+,
- +check_box+, +secure_password+, +file_field+.
-
-* +select+ and +radio_group+ operate in basically the same way; they both
- provide a method of selecting one out of several choices (ignoring
- <tt>select :multiple</tt>, that is). Note that select's list of choices,
- normally the second parameter to the select helper, has been relegated to a
- <tt>:choices</tt> entry in the options, for API consistency.
-
-* +static_text+ just outputs an HTML-escaped string representation of the
- field's value. It is useful both for read-only fields in forms, and as the
- primary helper in lists.
-
-* +calculated_text+ requires a block to which it will yield the model
- instance; the block's product will be treated like a string and
- HTML-escaped.
-
-* +static_html+ is like +static_text+, but the final product will not be
- HTML-escaped.
-
-* +calculated_html+ is like +calculated_text+, but the final product will not
- be HTML-escaped.
-
-* +auto_field+, as discussed above, will automatically select a suitable field
- helper, based on the column and association metadata. Where there are
- multiple suitable candidates, it tries to go for the more
- generally-applicable choice (for example, it favours a +select+ over a
- +radio_group+ for a +belongs_to+ association).
-
-* +static_image+ sports a number of options used to build an hash suitable for
- the +tag+ helper responsible for the creation of final <tt><img></tt> tag:
-
- * <tt>:controller</tt> (default "auto_admin") and <tt>:action</tt> (default
- "edit") allows to select a controller which should return the image based
- upon this object's id;
-
- * <tt>:src</tt> override the previous two options and can be used with any
- URL, static or dynamic;
-
- * with <tt>:size</tt> one can write the width and height used to show the
- image (format: "XxY");
-
- * <tt>:alt</tt>, which defaults to this object's +to_label+.
-
- Everything else is passed as is to the +tag+ helper (so one could use
- <tt>:style</tt> or <tt>:class</tt> to alter the looks of <tt><img></tt>).
- This helper accepts a block, with a single parameter (this object), which
- can be used to return an hash to be merged into the options that are about
- to be passed to the tag helper.
-
-* +text_field_with_auto_complete+ provides a simple text field with
- autocompletion delegating all the work to the homonymous ActionView's
- helper; there's a complication, however: there must be a separate controller
- which provides the completion data:
-
- b.text_field_with_auto_complete :name,
- :completion => { :url => { :controller => 'items',
- :action => 'auto_complete_for_item_name' }}
-
- For information on this controller, see Rails documentation. Note that if
- you designed your application in a REST-like way, you should tweak your
- resources' definitios or add a specific route for the new
- <tt>auto_complete_for_<em>model</em>_<em>field</em></tt>.
-
-* +hyperlink+ automatically generates a link to the "edit view" of its first
- argument (which must be one of the primary objects); alternatively you can
- use the <tt>:url</tt> option to generate a custom link:
-
- f.hyperlink :picture, :url => f.object.picture.url
-
- Anyway, the link caption will be the URL itself, unless you use the option
- <tt>:link_text</tt> as follow:
-
- f.hyperlink :picture, :url => f.object.picture.url,
- :link_text => 'The picture'
-
-* None of the following actually work, but they're defined, waiting for me to
- come back and write them. +html_area+ will eventually use FCKeditor by
- default, and presumably the file/image fields will delegate to file_column:
- +html_area+, +image_field+, +static_file+.
-
-
-== How does it work? - Part II, Themes
-
-The theme bundled with the plugin is named 'django'; all credit for its
-excellent appearance goes to the Django project. I hope we can get a couple of
-standard themes, but they won't be coming from me... experience shows that I
-shouldn't try to make things look good. I believe I've successfully drawn
-lines in all the right places for what is in the plugin's core, and what's in
-a theme. I've already developed most of a second theme (which will not be
-released) for my employer, so the infrastructure is mostly proven. A more
-coherent HOWTO on creating themes (which can just be installed as seperate
-Rails plugins, then selected in environment.rb) will be forthcoming Real Soon
-Now, though this section has ended up covering most of the basics.
-
-The 30 second summary -- a theme comprises:
-
-* FormBuilder (subclass of AutoAdminSimpleTheme::FormBuilder), to create an
- Edit screen (a real form)
-
-* TableBuilder (subclass of AutoAdmin::TableBuilder(FormBuilder)), to create a
- List screen (a creative interpretation of "form", which seems to map
- surprisingly well, for now).
-
-* FormProcessor (subclass of AutoAdminSimpleTheme::FormProcessor), which
- implements the same set of helper methods as the FormBuilders, but instead
- of returning HTML, its job is to perform any transformations on the params
- hash to correspond with unusual form field representations -- the base
- FormProcessor transforms keys referencing associations to reference the
- underlying columns (actor -> actor_id), for example. This class will often
- be empty, especially once I provide a facility with which to inject custom
- field helpers (for composed_of and maybe some belongs_to, mostly) into the
- base builder and processor.
-
-* A complete set of views, including a layout, which delegate the hard work to
- the FormBuilders.
-
-* A 'public' directory, containing any required image, javascript, and
- stylesheet assets.
-
-* A wrapper module, AutoAdmin#{name}Theme, which is responsible for:
-
- * Containing the FormBuilders and FormProcessor
-
- * Returning the full filesystem path to the 'views' and 'public' directories
-
- * Returing any theme-specific helpers, for injection into the controller
-
- * Injecting any theme-specific includes for ActiveRecord::Base (I've proven
- this to be possible, though can't think of a sane reason a theme would
- want to do so)
-
-Extending your theme module with AutoAdmin::ThemeHelpers will help to keep the
-module fairly DRY; it provides a +helper+ method, which can be given a list of
-modules and/or a block, and directs the 'view_directory' and 'asset_root'
-methods to a directory(*subdirs) singleton method, which you must define --
-presumably using \_\_FILE\_\_.
-
-NB: For good reasons that I can't remember right now, a couple of helper
-methods have APIs that don't match the standard Rails FormBuilder, despite
-matching names. The one that comes to mind is +select+ -- the choices have
-been moved into the options hash, to keep all method signatures of the form
-(field_name, options, *other_stuff).
-
-
-== What's planned, but missing?
-
-The ability for the application to inject custom field types into the base
-FormBuilder and FormProcessor. The theme-specific versions of these classes
-are available so that, for example, a theme can decide how a date_field should
-be presented, and can correspondingly recover the values from multiple
-inputs... they don't map as well to an application's requirement for a
-'currency' field. Of course, there's nothing stopping an application
-re-opening the classes and adding an appropriate helper method to each...
-there's just a bit of undesirable complexity involved if you want auto_field
-to detect and use it (which suggests to me that auto_field needs a bit of a
-rethink).
-
-A way for the application to reliably extend the AutoAdminController, and add
-appropriate views somewhere, for those occasions when you have a couple of
-screens that need to be hand-crafted, such as a statistics display, or a
-particular edit screen that needs a specialised workflow. Note that if you
-feel this constraint too much, you're probably pushing the plugin into a role
-it doesn't fit.
-
-Simple methods allowing an application to add navigation options, and perhaps
-the ability to insert Components into the "dashboard" on the index page?
-
-A top-level "menu", containing links to the primary object lists by default,
-that a theme can permanently display.
-
-
-== Longer-term architectural considerations?
-
-After starting off defining the administration interfaces directly in the
-models (as Django does), I was strongly considering moving them all into an
-application-specific controller, that would subclass AutoAdminController. I
-haven't gotten around to doing that, and am now quite intruiged by the
-approach taken by Streamlined -- adding a new type of class. Any such move is
-primarily aimed at solving a problem I'm not yet sufferring, though, so for
-now it's just a topic to ponder.
View
1 README.rdoc
View
484 README.rdoc
@@ -0,0 +1,484 @@
+= Rails AutoAdmin Plugin
+
+== What is it?
+
+A plugin for Ruby on Rails that automagically creates an administration
+interface, based on your models. It is heavily inspired by the
+Django[http://www.djangoproject.com/] administration system, and the only
+theme currently available is based directly on Django's administration system.
+From the screenshots posted so far, it appears to share goals with
+Streamlined[http://streamlined.relevancellc.com/].
+
+
+== Example?
+
+ class Customer < ActiveRecord::Base
+ belongs_to :store
+ has_many :payments, :order => 'payment_date DESC'
+
+ def name; first_name + ' ' + last_name; end
+
+ refresh_time 5
+ sort_by :last_name
+ search_by :first_name, :last_name
+ filter_by :active, :store
+ default_filter :active => true
+ list_columns :store, :first_name, :last_name
+
+ admin_fieldset do |b|
+ b.text_field :first_name
+ b.text_field :last_name
+ b.auto_field :active
+ b.select :store
+ end
+ admin_child_table 'Payments', :payments do |b|
+ b.static_text :payment_date
+ b.static_text :amount
+ end
+ end
+
+
+== What isn't it?
+
+Scaffolding. This is not a view generator for you to then customise. Either it
+provides the interface you want, or it doesn't. (With a limited, but hopefully
+expanding, set of exceptions.)
+
+For everyone. This is for applications that have a public interface and a
+restricted-access administrative interface. Its goal is not to generate views
+you would otherwise have to craft manually, so much as generating views you
+otherwise wouldn't bother to create. Of course, a neat side-effect of using
+this is that your boss (or your client's IT manager) can make simple
+database-level changes that would otherwise require a developer to use either
+the console or direct SQL. If you're trying to create an interface for all
+your users, this probably isn't for you.
+
+
+== Where is it?
+
+The public git repository is hosted by Github[http://github.com] and can be
+reached starting from http://github.com/baldowl/auto_admin
+
+I cannot stress enough that this is just a fork of the original code written
+by Matthew Draper; if you prefer the original version, then get it from the
+Subversion repository at http://svn.trebex.net/auto-admin/trunk/auto-admin
+
+
+== What does it assume?
+
+All objects it encounters can be usefully represented to a human as a string.
+It achieves this by adding a +to_label+ method to +Object+, which will return
+the first available of +label+, +name+, +to_s+ or +inspect+.
+
+Your access control requirements for the administration section are relatively
+"all or nothing". I intend to add simple class- and fieldset- level
+declarative permission checking soonish (whenever I start to need it). Access
+control based on querying individual objects should come at some point, but I
+don't anticipate needing that level of control any time soon. You can
+currently customise which fields are displayed (the field list is a block of
+code, after all), but will end up with empty fieldsets if you don't include
+any.
+
+If you have any access control (which I expect will pretty much always be the
+case), you must specify it with the <tt>admin_model=</tt> and
+<tt>admin_model_id=</tt> methods in the configuration block of AutoAdmin; the
+class must respond to +authenticate+, +login+, or
++find_by_username_and_password+ and that method must take two strings and
+return +nil+ for failure or a non-false value for success. It *must* return
+the authenticated user's id (or, in a less ideal turn, the user object itself:
+we will extract the id by ourself) -- the id will be stored in the session
+using the key provided by +admin_model_id+ and the currently logged-in user
+will be looked for; if the returned value responds to one or more of
+<tt>active?</tt>, <tt>enabled?</tt>, <tt>disabled?</tt> or <tt>admin?</tt>,
+they will be treated appropriately. So if other parts of your site do the
+same, things will Just Work.
+
+
+=== History
+
+Admins' actions are automatically recorded and shown if the optional
+<tt>admin_histories</tt> table is available.
+
+See AutoAdminController#history for details.
+
+
+== What do you need?
+
+To use AutoAdmin with Rails 2.* you need an extra plugin,
+will_paginate[http://github.com/mislav/will_paginate], because the pagination
+mechanism has been removed from the Rails core base.
+
+To use the +text_field_with_auto_complete+ helper you need an extra plugin,
+auto_complete[http://github.com/rails/auto_complete], because the
+autocompletion mechanism has been removed from the Rails core base.
+
+For the optional export mechanism you also need:
+
+* the *faster_csv* gem for the CSV export module;
+
+* the <b>pdf-writer</b> gem for the PDF export module.
+
+
+== How do I use it?
+
+Initially (after installing the plugin, obviously), you need to add a few
+lines to the bottom of your environment.rb or in an initializer file:
+
+ AutoAdmin.config do |admin|
+ # This information is used by the theme to construct a useful
+ # header; the first parameter is the full URL of the main site, the
+ # second is the displayed name of the site, and the third (optional)
+ # parameter is the title for the administration site.
+ admin.set_site_info 'http://www.example.com/', 'example.com',
+ 'Administration area for example.com'
+
+ # "Primary Objects" are those for which lists should be directly
+ # accessible from the home page.
+ admin.primary_objects = %w(actor film user)
+
+ admin.theme = :django # Optional; this is the default.
+
+ # The configurable, optional access control system.
+ admin.admin_model = Account
+ admin.admin_model_id = :account_id
+
+ # The optional export mechanism.
+ admin.save_as = %w(pdf csv)
+ end
+
+Having done that, you can now (re-)start <tt>script/server</tt>, and navigate
+to http://localhost:3000/admin/. Yes, it installs its own routes, but they are
+partially configurable; for now, just don't try to use <tt>/admin/</tt> for
+anything else.
+
+To customise which fields appear in the edit and list screens, you go on to...
+
+
+== How does it work? - Part I, Declarative UI definition
+
+The plugin adds a number of singleton methods to ActiveRecord::Base, which
+permit you to declare how the administration interface should behave.
+
+This set of methods, which are quite central to the utility of the plugin,
+have grown rather organically, over a period of time (as has my Ruby-fu). I've
+attempted to clear out the most glaring API inconsitencies, but it's still a
+bit of a mess. Some of the implementations definitely leave a bit to be
+desired. Cleaning this up is near the top of my TODO list. That said, it
+should all work. :)
+
+I really need to go through and write decent documentation for all the
+published methods, but for now, the following summary should at least act as a
+guide. Essentially, inside the model, you can use the following methods:
+
+[object_group(group_name)]
+ Declares which 'object group' this object belongs to, for use in the
+ interface. Currently, this is used to group together related objects on the
+ index page.
+
+[refresh_time(seconds)]
+ Instructs the list view to meta-refresh with the specified delay.
+
+[sort_by(column, reverse=false)]
+ Instructs the list view to sort on the specified column by default.
+
+[search_by(*columns)]
+ Add rudimentary text searching across the named columns. Note that this
+ defines a <tt>MyModel.search(many, query, options={})</tt> wrapper around
+ <tt>MyModel.find(many, options)</tt>.
+
+[filter_by(*columns)]
+ Allow filtering of the list screen by the named columns (filtering currently
+ works for: custom, boolean, date, belongs_to, has_one, and string). Note
+ that the last three will do rather nasty and sub-optimal queries to
+ determine the filter options.
+
+[default_filter(filters)]
+ Takes a hash of (column, value) pairs, to default a filter to something
+ other than 'All'.
+
+[filter_options_for(column, choices, &block)]
+ Specifies a fixed set of choices to be offered as filter options instead of
+ automatically working it out. Choices should be a (value, label) hash. The
+ optional block will be given each value in turn, and should return an SQL
+ condition fragment.
+
+[column_labels(labels)]
+ Takes a hash of (column, label) pairs, to change the default label for a
+ field to explicitly define the human label for a column. This label will be
+ the default used in both list and edit views.
+
+[list_columns(*columns, &proc)]
+ Takes either a simple-list of column names, or a Field Definition Block (see
+ next section) or both.
+
+ Please, note that a list of column names will produce a bunch of fields
+ using the +static_text+ helper almost for everything but the first column
+ (which will get a special treatment to allow you to access the "edit view").
+ If a column occurs more than once (summing up the list of column names and
+ the FDB), then that column will appear more than once:
+
+ list_columns :name, :code, :address do |f|
+ f.hyperlink :address
+ end
+
+ The previous code fragment will list the +address+ column twice: the first
+ one will be shown as static text, the second one will produce a real link.
+
+ At the moment, if you have a long list of columns and want to customize only
+ a few of them, you have to write then down one by one, even those that don't
+ need special care.
+
+[admin_fieldset(label='', *columns, &proc)]
+ Defines a fieldset for edit views. For simple use, you can just give it a
+ list of columns. Once you get started, you'll want to pass a Field
+ Definition Block, though.
+
+ In the Field Definition Block you can get hold of the model instance using
+ the block's parameter; let's say the model has an attachment, handled by
+ paperclip[http://github.com/thoughtbot/paperclip], called +picture+ and you
+ want to show the image's URL like an hyperlink:
+
+ admin_fieldset do |f|
+ # ...
+ f.hyperlink :picture, :url => f.object.picture.url
+ end
+
+ At the moment, this does not work with +list_columns+.
+
+ Most of the helpers which accept or require a block will yield the model
+ instance to the block, if it requires a parameter:
+
+ admin_fieldset do |f|
+ # ...
+ f.static_image :picture do |cover|
+ {:src => cover.picture.url}
+ end
+ end
+
+ This works also with +list_columns+.
+
+[admin_child_table(label, collection, options={}, &proc)]
+ Defines a fieldset for edit views, to show a table of items from a child
+ collection. It uses a Field Definition Block to declare what columns should
+ be shown. Generally, you'd want to use the static_text helper, I suspect.
+ *WARNING*: This has no tests, and I'm almost certain it will break horribly
+ if you try to use anything other than static_text.
+
+[admin_child_form(collection, options={}, &proc)]
+ Defines a "fieldset" for edit views, to show *several* fieldsets, each
+ containing one object from a child collection. It uses a Field Definition
+ Block to declare what columns should be shown. I don't think it'd be wise to
+ use this on a large collection, but it's your application. :) *WARNING*:
+ This also has no tests, and I believe it will break horribly if you try to
+ use it at all.
+
+
+== Field Definition Block?!?
+
+A number of the above methods provide for a block to declare what fields are
+to be shown. This is achieved by yielding a builder to the block. Depending on
+context, the mood of a theme author, and the phase of the moon, a given block
+will see several builders in its lifetime. Not all builders will have an
+active object; all will respond to the +object+ method, though. A basic field
+definition block will just call a field helper on the builder for each field
+that it wishes to display. The +auto_field+ helper (which automatically
+determines an appropriate field type based on column and association metadata)
+is available if you only want to specify the field type for some of the
+fields. All field helpers take <tt>(field_name, options={},
+*other_stuff)</tt>. Most just take the two parameters, and I'm considering
+deprecating the extra parameters on those that currently support them. Note
+that unlike a standard builder, you don't have to do anything with the return
+value; the theme's actual FormBuilder is wrapped by a DeclarativeFormBuilder,
+which takes care of that for you.
+
+In theory, there's no compelling reason you can't add complex logic to a field
+definition block, such as examining the current user, or even the builder's
+active object (though I strongly encourage you to handle nil permissively, at
+this stage). It would be unwise to vary the fields returned based on the
+object for a list view, for fairly obvious reasons.
+
+
+== Available Form Helpers
+
+* Simple helpers that just delegate to the ActionView's FormBuilder:
+ +hidden_field+, +date_select+, +datetime_select+, +text_field+, +text_area+,
+ +check_box+, +secure_password+, +file_field+.
+
+* +select+ and +radio_group+ operate in basically the same way; they both
+ provide a method of selecting one out of several choices (ignoring
+ <tt>select :multiple</tt>, that is). Note that select's list of choices,
+ normally the second parameter to the select helper, has been relegated to a
+ <tt>:choices</tt> entry in the options, for API consistency.
+
+* +static_text+ just outputs an HTML-escaped string representation of the
+ field's value. It is useful both for read-only fields in forms, and as the
+ primary helper in lists.
+
+* +calculated_text+ requires a block to which it will yield the model
+ instance; the block's product will be treated like a string and
+ HTML-escaped.
+
+* +static_html+ is like +static_text+, but the final product will not be
+ HTML-escaped.
+
+* +calculated_html+ is like +calculated_text+, but the final product will not
+ be HTML-escaped.
+
+* +auto_field+, as discussed above, will automatically select a suitable field
+ helper, based on the column and association metadata. Where there are
+ multiple suitable candidates, it tries to go for the more
+ generally-applicable choice (for example, it favours a +select+ over a
+ +radio_group+ for a +belongs_to+ association).
+
+* +static_image+ sports a number of options used to build an hash suitable for
+ the +tag+ helper responsible for the creation of final <tt><img></tt> tag:
+
+ * <tt>:controller</tt> (default "auto_admin") and <tt>:action</tt> (default
+ "edit") allows to select a controller which should return the image based
+ upon this object's id;
+
+ * <tt>:src</tt> override the previous two options and can be used with any
+ URL, static or dynamic;
+
+ * with <tt>:size</tt> one can write the width and height used to show the
+ image (format: "XxY");
+
+ * <tt>:alt</tt>, which defaults to this object's +to_label+.
+
+ Everything else is passed as is to the +tag+ helper (so one could use
+ <tt>:style</tt> or <tt>:class</tt> to alter the looks of <tt><img></tt>).
+ This helper accepts a block, with a single parameter (this object), which
+ can be used to return an hash to be merged into the options that are about
+ to be passed to the tag helper.
+
+* +text_field_with_auto_complete+ provides a simple text field with
+ autocompletion delegating all the work to the homonymous ActionView's
+ helper; there's a complication, however: there must be a separate controller
+ which provides the completion data:
+
+ b.text_field_with_auto_complete :name,
+ :completion => { :url => { :controller => 'items',
+ :action => 'auto_complete_for_item_name' }}
+
+ For information on this controller, see Rails documentation. Note that if
+ you designed your application in a REST-like way, you should tweak your
+ resources' definitios or add a specific route for the new
+ <tt>auto_complete_for_<em>model</em>_<em>field</em></tt>.
+
+* +hyperlink+ automatically generates a link to the "edit view" of its first
+ argument (which must be one of the primary objects); alternatively you can
+ use the <tt>:url</tt> option to generate a custom link:
+
+ f.hyperlink :picture, :url => f.object.picture.url
+
+ Anyway, the link caption will be the URL itself, unless you use the option
+ <tt>:link_text</tt> as follow:
+
+ f.hyperlink :picture, :url => f.object.picture.url,
+ :link_text => 'The picture'
+
+* None of the following actually work, but they're defined, waiting for me to
+ come back and write them. +html_area+ will eventually use FCKeditor by
+ default, and presumably the file/image fields will delegate to file_column:
+ +html_area+, +image_field+, +static_file+.
+
+
+== How does it work? - Part II, Themes
+
+The theme bundled with the plugin is named 'django'; all credit for its
+excellent appearance goes to the Django project. I hope we can get a couple of
+standard themes, but they won't be coming from me... experience shows that I
+shouldn't try to make things look good. I believe I've successfully drawn
+lines in all the right places for what is in the plugin's core, and what's in
+a theme. I've already developed most of a second theme (which will not be
+released) for my employer, so the infrastructure is mostly proven. A more
+coherent HOWTO on creating themes (which can just be installed as seperate
+Rails plugins, then selected in environment.rb) will be forthcoming Real Soon
+Now, though this section has ended up covering most of the basics.
+
+The 30 second summary -- a theme comprises:
+
+* FormBuilder (subclass of AutoAdminSimpleTheme::FormBuilder), to create an
+ Edit screen (a real form)
+
+* TableBuilder (subclass of AutoAdmin::TableBuilder(FormBuilder)), to create a
+ List screen (a creative interpretation of "form", which seems to map
+ surprisingly well, for now).
+
+* FormProcessor (subclass of AutoAdminSimpleTheme::FormProcessor), which
+ implements the same set of helper methods as the FormBuilders, but instead
+ of returning HTML, its job is to perform any transformations on the params
+ hash to correspond with unusual form field representations -- the base
+ FormProcessor transforms keys referencing associations to reference the
+ underlying columns (actor -> actor_id), for example. This class will often
+ be empty, especially once I provide a facility with which to inject custom
+ field helpers (for composed_of and maybe some belongs_to, mostly) into the
+ base builder and processor.
+
+* A complete set of views, including a layout, which delegate the hard work to
+ the FormBuilders.
+
+* A 'public' directory, containing any required image, javascript, and
+ stylesheet assets.
+
+* A wrapper module, AutoAdmin#{name}Theme, which is responsible for:
+
+ * Containing the FormBuilders and FormProcessor
+
+ * Returning the full filesystem path to the 'views' and 'public' directories
+
+ * Returing any theme-specific helpers, for injection into the controller
+
+ * Injecting any theme-specific includes for ActiveRecord::Base (I've proven
+ this to be possible, though can't think of a sane reason a theme would
+ want to do so)
+
+Extending your theme module with AutoAdmin::ThemeHelpers will help to keep the
+module fairly DRY; it provides a +helper+ method, which can be given a list of
+modules and/or a block, and directs the 'view_directory' and 'asset_root'
+methods to a directory(*subdirs) singleton method, which you must define --
+presumably using \_\_FILE\_\_.
+
+NB: For good reasons that I can't remember right now, a couple of helper
+methods have APIs that don't match the standard Rails FormBuilder, despite
+matching names. The one that comes to mind is +select+ -- the choices have
+been moved into the options hash, to keep all method signatures of the form
+(field_name, options, *other_stuff).
+
+
+== What's planned, but missing?
+
+The ability for the application to inject custom field types into the base
+FormBuilder and FormProcessor. The theme-specific versions of these classes
+are available so that, for example, a theme can decide how a date_field should
+be presented, and can correspondingly recover the values from multiple
+inputs... they don't map as well to an application's requirement for a
+'currency' field. Of course, there's nothing stopping an application
+re-opening the classes and adding an appropriate helper method to each...
+there's just a bit of undesirable complexity involved if you want auto_field
+to detect and use it (which suggests to me that auto_field needs a bit of a
+rethink).
+
+A way for the application to reliably extend the AutoAdminController, and add
+appropriate views somewhere, for those occasions when you have a couple of
+screens that need to be hand-crafted, such as a statistics display, or a
+particular edit screen that needs a specialised workflow. Note that if you
+feel this constraint too much, you're probably pushing the plugin into a role
+it doesn't fit.
+
+Simple methods allowing an application to add navigation options, and perhaps
+the ability to insert Components into the "dashboard" on the index page?
+
+A top-level "menu", containing links to the primary object lists by default,
+that a theme can permanently display.
+
+
+== Longer-term architectural considerations?
+
+After starting off defining the administration interfaces directly in the
+models (as Django does), I was strongly considering moving them all into an
+application-specific controller, that would subclass AutoAdminController. I
+haven't gotten around to doing that, and am now quite intruiged by the
+approach taken by Streamlined -- adding a new type of class. Any such move is
+primarily aimed at solving a problem I'm not yet sufferring, though, so for
+now it's just a topic to ponder.

0 comments on commit 562cd41

Please sign in to comment.